@designbasekorea/ui-wc 0.9.0 → 0.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/README.md +18 -2
- package/dist/esm/components/date-picker-utils.js +1 -1
- package/dist/esm/components/db-accordion.js +1 -1
- package/dist/esm/components/db-achievement-list.js +1 -1
- package/dist/esm/components/db-achievement-modal.js +1 -1
- package/dist/esm/components/db-activity-heatmap.js +1 -1
- package/dist/esm/components/db-ad-banner.js +1 -1
- package/dist/esm/components/db-ai-chat-list.js +1 -1
- package/dist/esm/components/db-ai-chat.js +1 -1
- package/dist/esm/components/db-alert.d.ts +12 -0
- package/dist/esm/components/db-alert.js +1 -1
- package/dist/esm/components/db-app-badge.js +1 -1
- package/dist/esm/components/db-audio-player.js +1 -1
- package/dist/esm/components/db-backdrop.js +1 -1
- package/dist/esm/components/db-boarding-pass-stack.js +1 -1
- package/dist/esm/components/db-boarding-pass.js +1 -1
- package/dist/esm/components/db-bottom-navigation.js +1 -1
- package/dist/esm/components/db-bottom-sheet.js +1 -1
- package/dist/esm/components/db-breadcrumbs.js +1 -1
- package/dist/esm/components/db-calendar.js +1 -1
- package/dist/esm/components/db-card.js +1 -1
- package/dist/esm/components/db-carousel.d.ts +3 -3
- package/dist/esm/components/db-carousel.js +1 -1
- package/dist/esm/components/db-chat-composer.js +1 -1
- package/dist/esm/components/db-chat-room.js +1 -1
- package/dist/esm/components/db-chat-widget.js +1 -1
- package/dist/esm/components/db-chip.js +1 -1
- package/dist/esm/components/db-code-block.js +1 -1
- package/dist/esm/components/db-color-picker.js +1 -1
- package/dist/esm/components/db-confirm.js +1 -1
- package/dist/esm/components/db-context-bar.js +1 -1
- package/dist/esm/components/db-context-menu.js +1 -1
- package/dist/esm/components/db-credit-card.js +1 -1
- package/dist/esm/components/db-cursor-follower.js +1 -1
- package/dist/esm/components/db-date-picker.js +1 -1
- package/dist/esm/components/db-design-canvas.js +1 -1
- package/dist/esm/components/db-design-toolbar.js +1 -1
- package/dist/esm/components/db-download-progress.js +1 -1
- package/dist/esm/components/db-drawer.d.ts +1 -0
- package/dist/esm/components/db-drawer.js +1 -1
- package/dist/esm/components/db-dropdown.js +1 -1
- package/dist/esm/components/db-dropzone.js +1 -1
- package/dist/esm/components/db-email-verify.d.ts +0 -6
- package/dist/esm/components/db-email-verify.js +1 -1
- package/dist/esm/components/db-file-uploader.js +1 -1
- package/dist/esm/components/db-flight-status.js +1 -1
- package/dist/esm/components/db-footer.js +1 -1
- package/dist/esm/components/db-gantt.js +1 -1
- package/dist/esm/components/db-image-list.d.ts +2 -0
- package/dist/esm/components/db-image-list.js +1 -1
- package/dist/esm/components/db-indicator.js +1 -1
- package/dist/esm/components/db-input.js +1 -1
- package/dist/esm/components/db-kanban.js +1 -1
- package/dist/esm/components/db-lightbox.d.ts +4 -0
- package/dist/esm/components/db-lightbox.js +1 -1
- package/dist/esm/components/db-markdown-editor.js +1 -1
- package/dist/esm/components/db-marquee.d.ts +2 -10
- package/dist/esm/components/db-marquee.js +1 -1
- package/dist/esm/components/db-modal.js +1 -1
- package/dist/esm/components/db-navbar.js +1 -1
- package/dist/esm/components/db-node.js +1 -1
- package/dist/esm/components/db-onboarding-modal.js +1 -1
- package/dist/esm/components/db-otp-input.js +1 -1
- package/dist/esm/components/db-page-header.d.ts +8 -0
- package/dist/esm/components/db-page-header.js +1 -1
- package/dist/esm/components/db-pagination.js +1 -1
- package/dist/esm/components/db-phone-verify.js +1 -1
- package/dist/esm/components/db-popover.js +1 -1
- package/dist/esm/components/db-progress-step.js +1 -1
- package/dist/esm/components/db-receipt.js +1 -1
- package/dist/esm/components/db-resizable-panels.js +1 -1
- package/dist/esm/components/db-search-bar.js +1 -1
- package/dist/esm/components/db-section-testimonials.d.ts +1 -4
- package/dist/esm/components/db-section-testimonials.js +1 -1
- package/dist/esm/components/db-segment-control.d.ts +0 -4
- package/dist/esm/components/db-segment-control.js +1 -1
- package/dist/esm/components/db-select.js +1 -1
- package/dist/esm/components/db-share.js +1 -1
- package/dist/esm/components/db-sidebar.js +1 -1
- package/dist/esm/components/db-split-view.js +1 -1
- package/dist/esm/components/db-stepper.d.ts +0 -3
- package/dist/esm/components/db-stepper.js +1 -1
- package/dist/esm/components/db-table.js +1 -1
- package/dist/esm/components/db-testimonial.js +1 -1
- package/dist/esm/components/db-time-picker.js +1 -1
- package/dist/esm/components/db-tooltip.js +1 -1
- package/dist/esm/components/db-top-banner.js +1 -1
- package/dist/esm/components/db-tutorial.js +1 -1
- package/dist/esm/components/db-two-factor.d.ts +4 -10
- package/dist/esm/components/db-two-factor.js +1 -1
- package/dist/esm/components/db-video-player.js +1 -1
- package/dist/esm/components/db-voice-control.js +1 -1
- package/dist/esm/components/db-youtube-player.js +1 -1
- package/dist/esm/components/input-validation.js +1 -1
- package/dist/esm/components/paper-card.js +1 -1
- package/dist/esm/core/focus-trap.js +1 -1
- package/dist/esm/core/host-class.js +1 -0
- package/dist/esm/core/i18n-copy.js +1 -0
- package/dist/esm/core/i18n-en.js +1 -0
- package/dist/esm/core/i18n.d.ts +65 -1
- package/dist/esm/core/i18n.js +1 -1
- package/dist/esm/core/theme-scope.js +1 -0
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/node_modules/@designbasekorea/carousel/dist/chunks/chunk-AGE5BHQ4.js +1 -0
- package/dist/esm/node_modules/@designbasekorea/carousel/dist/chunks/chunk-GM4TCAP5.js +1 -0
- package/dist/esm/node_modules/@designbasekorea/carousel/dist/chunks/chunk-GSN4JZN7.js +1 -0
- package/dist/esm/node_modules/@designbasekorea/carousel/dist/chunks/chunk-VJJVQGV4.js +1 -0
- package/dist/esm/node_modules/@designbasekorea/carousel/dist/chunks/chunk-YWLMJGDH.js +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.ts +100 -41
- package/dist/index.esm.js +1 -1
- package/dist/react/index.cjs +1 -1
- package/dist/react/index.d.ts +12 -0
- package/dist/react/index.esm.js +1 -1
- package/package.json +5 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,36 @@
|
|
|
1
1
|
# 변경 이력
|
|
2
2
|
|
|
3
|
+
## 0.9.3 - 2026-10-26
|
|
4
|
+
|
|
5
|
+
Pro 템플릿(AI Assistant·Docs) 제작 중 발견한 라이브러리 버그 수정 릴리스입니다.
|
|
6
|
+
|
|
7
|
+
- ChatComposer: 전송·정지·첨부 버튼 접근성 이름과 placeholder 기본값이 `dbUseLocale('en')`을 따르도록 i18n 키(`chatComposer.*`)로 이동. `send-label`이 실제로 전송 버튼에 적용되고, `stop-label`·`attach-label`(React `stopLabel`·`attachLabel`)을 추가. 드롭 오버레이 문구도 번역됩니다.
|
|
8
|
+
- VoiceControl: 시작·완료·취소 라벨과 상태 문구를 i18n 키(`voice.*`)로 이동. `start-label`·`stop-label`·`cancel-label`은 계속 우선합니다.
|
|
9
|
+
- i18n: 영어 로케일에서 `dbText('첨부')`가 "Added"로 나오던 번역 오류를 "Attach"로 수정. "~ 추가" 버튼 문구("Add color" 등)와 첨부 메뉴·음성 입력 문구의 영어 번역도 바로잡음.
|
|
10
|
+
- Select, Dropdown, AiChatList, CodeBlock, ChatComposer, Alert: 렌더할 때 호스트의 `class`를 통째로 덮어써 소비자 클래스(React `className` 포함)가 사라지던 문제 수정. 컴포넌트는 자기 클래스만 추가·제거합니다(`core/host-class`).
|
|
11
|
+
- Alert: 자식 콘텐츠(링크·`code`·텍스트 등)를 본문 아래 슬롯에 렌더합니다. 재렌더해도 유지되고 나중에 추가된 자식도 반영됩니다. React `<Alert>`는 순수 텍스트 자식은 기존처럼 `message`로, 요소가 섞인 자식은 실제 DOM으로 전달합니다.
|
|
12
|
+
- **동작 변경** Alert: 닫기 버튼이 옵트인으로 바뀌었습니다. `closable` 속성(React `closable`)을 줄 때만 표시합니다. 이전처럼 닫기 버튼이 필요하면 `closable`을 추가하세요.
|
|
13
|
+
- 호스트 클래스: React `className`이 나중에 바뀌어 class 속성이 다시 쓰여도 컴포넌트 소유 클래스를 즉시 복원합니다.
|
|
14
|
+
- 회귀 테스트: `npm run test:template-fixes` (`scripts/test-ui-wc-template-fixes.mjs`, 빌드된 dist를 Chromium에서 검증).
|
|
15
|
+
|
|
16
|
+
## 0.9.2 - 2026-10-24
|
|
17
|
+
|
|
18
|
+
`@designbasekorea/ui-wc` 컴포넌트 패키지 단독 릴리스입니다. 현재 WC/React 컴포넌트와 스타일·타입 선언을 재빌드하며 examples, blocks, 페이지 템플릿은 배포 대상에 포함하지 않습니다.
|
|
19
|
+
|
|
20
|
+
- PageHeader의 sticky·스크롤 압축·격자 배경·count 및 React meta 슬롯 컨트롤 보존 개선 반영.
|
|
21
|
+
- Carousel·ImageList·Lightbox·SectionTestimonials의 공통 Carousel 엔진 연결, Marquee·SectionLogoCloud의 Motion/Ticker 연결과 Indicator progress 지원 반영.
|
|
22
|
+
- 현재 컴포넌트 구현, 공통 유틸리티, React wrapper 및 개별 컴포넌트 진입점의 수정 사항 반영.
|
|
23
|
+
- ESM/CJS, CSS와 TypeScript 선언을 함께 제공하며 전체·React·개별 경로 사용을 배포 패키지 기준으로 검증.
|
|
24
|
+
|
|
25
|
+
## 0.9.1 - 2026-10-23
|
|
26
|
+
|
|
27
|
+
- PageHeader: `sticky`, `compact-on-scroll`, `background="grid"`, `count` 추가. 스크롤 압축 시 제목·필터를 유지하고 격자 배경을 숨깁니다. `--db-page-header-sticky-offset`으로 상단 앱 바 높이를 지정합니다.
|
|
28
|
+
- PageHeader: React 초기 렌더에서 `meta` 슬롯의 실제 Select 등 컨트롤이 유실되는 문제 수정.
|
|
29
|
+
|
|
30
|
+
- Carousel, ImageList의 carousel 레이아웃, Lightbox, SectionTestimonials의 carousel 변형을 `@designbasekorea/carousel` 엔진으로 통합했습니다.
|
|
31
|
+
- Marquee와 SectionLogoCloud의 흐르는 콘텐츠는 같은 패키지의 Motion/Ticker를 사용합니다. 호버 정지, 여러 행의 교차 방향, 스크롤 속도 연동과 움직임 감소 설정을 유지합니다.
|
|
32
|
+
- Indicator에 외부 재생 진행률을 받는 `progress` 속성을 추가했습니다. Carousel의 자동 재생과 Indicator가 하나의 시계를 공유합니다.
|
|
33
|
+
|
|
3
34
|
## 0.9.0 - 2026-10-22
|
|
4
35
|
|
|
5
36
|
컴포넌트 패키지 `@designbasekorea/ui-wc` 단독 릴리스입니다. `@designbasekorea/blocks`, 페이지 템플릿과 갤러리 서비스는 이 npm 배포에 포함하지 않습니다.
|
package/README.md
CHANGED
|
@@ -22,9 +22,9 @@ npm run audit:axe # axe-core 런타임 접근성 검증 (build 선행 필
|
|
|
22
22
|
npm run verify:docs # 문서 ↔ 구현 정합성
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
## 크레딧·충전·AI 작업 UI
|
|
25
|
+
## 크레딧·충전·AI 작업 UI
|
|
26
26
|
|
|
27
|
-
`CreditBalance`, `CreditRecharge`, `AiTaskStatus`, `CreditDropdown`, `CreditRechargeModal`의 Web Component/React API와 서버 연결 경계는 [사용 안내](./docs/CREDIT-AI.md)를 따릅니다.
|
|
27
|
+
`CreditBalance`, `CreditRecharge`, `AiTaskStatus`, `CreditDropdown`, `CreditRechargeModal`의 Web Component/React API와 서버 연결 경계는 [사용 안내](./docs/CREDIT-AI.md)를 따릅니다. 0.9.x 배포에 포함된 컴포넌트입니다.
|
|
28
28
|
|
|
29
29
|
## 최근 변경
|
|
30
30
|
|
|
@@ -530,3 +530,19 @@ AI 대화·작업 과정·출처·도구 결과는 [AI Elements](./docs/AI-ELEME
|
|
|
530
530
|
저장소 루트에서 `npm run ui-wc:build`로 공유 계약과 ui-wc만 빌드하고, `npm run publish:ui-wc`로 `@designbasekorea/ui-wc`만 npm에 배포합니다. 이 명령은 blocks·템플릿·갤러리를 배포하지 않습니다. 갤러리 전체 빌드는 `npm run example:gallery:build`가 blocks 빌드를 별도로 실행합니다.
|
|
531
531
|
|
|
532
532
|
npm 배포물에는 ui-wc의 `dist`, README·변경 이력과 결제 로고 라이선스 고지만 포함됩니다. 신규 컴포넌트는 전체 진입점·React 래퍼·개별 import에서 사용할 수 있습니다. 결제·초대·AI 요청·저장 같은 실제 서버 동작은 소비 앱에서 연결합니다.
|
|
533
|
+
|
|
534
|
+
### 스크롤하면 작아지는 페이지 헤더
|
|
535
|
+
|
|
536
|
+
```tsx
|
|
537
|
+
import { PageHeader, Select, SegmentControl, Sidebar } from '@designbasekorea/ui-wc/react';
|
|
538
|
+
|
|
539
|
+
<PageHeader title="전체 블록" count={80} description="필요한 블록을 찾아보세요."
|
|
540
|
+
variant="minimal" background="grid" sticky compactOnScroll>
|
|
541
|
+
<Select slot="meta" value="all" options={categories} onChange={onCategoryChange} />
|
|
542
|
+
<SegmentControl slot="actions" value="all" options={tiers} onChange={onTierChange} />
|
|
543
|
+
</PageHeader>
|
|
544
|
+
|
|
545
|
+
<Sidebar type="navigation" sections={sections} />
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
`sticky`는 가장 가까운 스크롤 영역의 상단에 고정합니다. `compactOnScroll`은 원래 위치를 지나면 설명과 격자를 숨기고 제목·개수·컨트롤을 유지합니다. 상단 앱 바가 있으면 헤더의 `--db-page-header-sticky-offset`에 해당 높이(예: `64px`)를 지정하세요. 별도 자바스크립트 스크롤 핸들러는 필요하지 않습니다. `Sidebar`의 `navigation` 타입은 문서·페이지 탐색에 사용합니다.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const startOfDay=t=>{const e=new Date(t);return e.setHours(0,0,0,0),e},endOfDay=t=>{const e=new Date(t);return e.setHours(23,59,59,999),e},addDays=(t,e)=>{const n=new Date(t);return n.setDate(n.getDate()+e),startOfDay(n)},getMonthEnd=t=>endOfDay(new Date(t.getFullYear(),t.getMonth()+1,0)),getYearEnd=t=>endOfDay(new Date(t.getFullYear(),11,31)),clampRange=(t,e,n)=>{let{start:a,end:r}=t;return e&&a<e&&(a=startOfDay(e)),n&&r>n&&(r=endOfDay(n)),a>r?{start:r,end:a}:{start:a,end:r}},
|
|
1
|
+
import{dbText as t,getDbLocale as e}from"../core/i18n.js";const startOfDay=t=>{const e=new Date(t);return e.setHours(0,0,0,0),e},endOfDay=t=>{const e=new Date(t);return e.setHours(23,59,59,999),e},addDays=(t,e)=>{const n=new Date(t);return n.setDate(n.getDate()+e),startOfDay(n)},getMonthEnd=t=>endOfDay(new Date(t.getFullYear(),t.getMonth()+1,0)),getYearEnd=t=>endOfDay(new Date(t.getFullYear(),11,31)),clampRange=(t,e,n)=>{let{start:a,end:r}=t;return e&&a<e&&(a=startOfDay(e)),n&&r>n&&(r=endOfDay(n)),a>r?{start:r,end:a}:{start:a,end:r}},n=[{id:"today",label:t("오늘"),getRange:({today:t})=>clampRange({start:startOfDay(t),end:endOfDay(t)})},{id:"yesterday",label:t("어제"),getRange:({today:t})=>{const e=addDays(t,-1);return clampRange({start:e,end:endOfDay(e)})}},{id:"this-week",label:t("이번 주"),getRange:({today:t,startOfWeek:e,minDate:n,maxDate:a})=>{const r=((t,e)=>{const n=t.getDay();return addDays(t,-("monday"===e?(n+6)%7:n))})(t,e);return clampRange({start:r,end:(o=r,endOfDay(addDays(o,6)))},n,a);var o}},{id:"this-month",label:t("이번 달"),getRange:({today:t,minDate:e,maxDate:n})=>{return clampRange({start:(a=t,startOfDay(new Date(a.getFullYear(),a.getMonth(),1))),end:getMonthEnd(t)},e,n);var a}},{id:"this-year",label:t("올해"),getRange:({today:t,minDate:e,maxDate:n})=>{return clampRange({start:(a=t,startOfDay(new Date(a.getFullYear(),0,1))),end:getYearEnd(t)},e,n);var a}},{id:"custom",label:t("사용자 지정"),getRange:()=>null}],addMonths=(t,e)=>{const n=new Date(t);return n.setDate(1),n.setMonth(n.getMonth()+e),n},toISODate=t=>`${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,"0")}-${String(t.getDate()).padStart(2,"0")}`,parseISODate=t=>{if(!t)return null;const e=t.trim().match(/^(\d{4})-(\d{2})-(\d{2})$/);if(!e)return null;const n=new Date(Number(e[1]),Number(e[2])-1,Number(e[3]));return Number.isNaN(n.getTime())?null:startOfDay(n)},formatDisplayDate=(t,n=("ko"===e()?"ko-KR":"en-US"))=>t.toLocaleDateString(n),generateWeekdays=(t,n=("ko"===e()?"ko-KR":"en-US"))=>{const a=Array.from({length:7},(t,e)=>new Intl.DateTimeFormat(n,{weekday:"short"}).format(new Date(2026,0,4+e)));return"monday"===t&&a.push(a.shift()),a},generateCalendarGrid=(t,e,n=!1)=>{const a=t.getFullYear(),r=t.getMonth(),o=new Date(a,r,1),s="monday"===e?(o.getDay()+6)%7:o.getDay();if(n){const t=[];for(let e=0;e<s;e+=1)t.push(null);const e=new Date(a,r+1,0).getDate();for(let n=1;n<=e;n+=1)t.push(new Date(a,r,n));return t}const u=new Date(o);return u.setDate(u.getDate()-s),Array.from({length:42},(t,e)=>{const n=new Date(u);return n.setDate(u.getDate()+e),n})},detectActivePresetId=(t,e,n)=>{if(!t)return"custom";const a=t.start.toDateString(),r=t.end.toDateString();for(const t of e){if("custom"===t.id)continue;const e=t.getRange(n);if(e&&(e.start.toDateString()===a&&e.end.toDateString()===r))return t.id}return"custom"},formatPanelInputDate=(t,e)=>t?t.toLocaleDateString(e,{year:"numeric",month:"short",day:"numeric"}):"";export{n as DEFAULT_DATE_PICKER_PRESETS,addMonths,detectActivePresetId,endOfDay,formatDisplayDate,formatPanelInputDate,generateCalendarGrid,generateWeekdays,parseISODate,startOfDay,toISODate};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{dbText as e}from"../core/i18n.js";import{createDbIcon as t}from"./db-icons.js";import{coerceToContract as s}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{ACCORDION_VARIANTS as n,ACCORDION_SIZES as i}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";class DbAccordion extends HTMLElement{constructor(){super(...arguments),this.expanded=new Set,this.isRendering=!1,this.suppressExpandedAttrCallback=!1}static get observedAttributes(){return["items","variant","size","allow-multiple","expand-mode","expanded-items","default-item-type"]}get items(){try{const e=JSON.parse(this.getAttribute("items")||"[]");return Array.isArray(e)?e:[]}catch{return[]}}set items(e){this.setAttribute("items","string"==typeof e?e:JSON.stringify(e))}get allowMultiple(){return this.hasAttribute("allow-multiple")}set allowMultiple(e){this.toggleAttribute("allow-multiple",e)}get expandedItems(){const e=(this.getAttribute("expanded-items")||"").trim();if(!e)return[];if("all"===e)return this.items.map((e,t)=>this.resolveItemKey(e,t));try{const t=JSON.parse(e);if(Array.isArray(t))return t.map(e=>String(e).trim()).filter(Boolean)}catch{}return e.split(",").map(e=>e.trim()).filter(Boolean)}set expandedItems(e){Array.isArray(e)?this.setAttribute("expanded-items",e.join(",")):this.setAttribute("expanded-items",e)}connectedCallback(){this.syncExpandedFromAttributes(),this.render(),this.childObserver=new MutationObserver(e=>{if(this.isRendering)return;e.some(e=>Array.from(e.addedNodes).some(e=>e instanceof HTMLElement&&e.hasAttribute("slot")))&&this.render()}),this.childObserver.observe(this,{childList:!0})}disconnectedCallback(){this.childObserver?.disconnect()}attributeChangedCallback(e){if(this.isConnected){if("expanded-items"===e){if(this.suppressExpandedAttrCallback)return;return this.syncExpandedFromAttributes(),void this.syncExpandedState()}return"expand-mode"===e||"allow-multiple"===e?(this.syncExpandedFromAttributes(),void this.syncExpandedState()):"items"===e?(this.syncExpandedFromAttributes(),void this.render()):void this.render()}}resolveItemKey(e,t){return e.id??String(t)}getExpandMode(){const e=this.getAttribute("expand-mode");return"single"===e||"multiple"===e||"all"===e?e:(this.hasAttribute("allow-multiple"),"multiple")}syncExpandedFromAttributes(){const e=this.items.map((e,t)=>this.resolveItemKey(e,t)),t=this.expandedItems,s=this.getExpandMode();t.length>0?this.expanded=new Set(t.filter(t=>e.includes(t))):this.expanded="all"!==s?new Set:new Set(e)}iconSize(e){return"s"===e?16:"l"===e?24:20}collectPanelContent(){const e=new Map,register=(t,s)=>{if(!(t instanceof HTMLElement)||"SLOT"===t.tagName)return;e.has(s)||e.set(s,[]);const n=e.get(s);n.includes(t)||n.push(t)};return Array.from(this.children).forEach(e=>{const t=e.getAttribute("slot")?.match(/^content-(\d+)$/);t&®ister(e,Number(t[1]))}),this.querySelectorAll(":scope > .designbase-wc-accordion__item").forEach((e,t)=>{const s=e.querySelector(":scope > .designbase-wc-accordion__content > .designbase-wc-accordion__content-inner");s&&Array.from(s.children).forEach(e=>register(e,t))}),e}isItemExpanded(e,t){return this.expanded.has(this.resolveItemKey(e,t))}syncExpandedState(){const e=this.items;this.querySelectorAll(":scope > .designbase-wc-accordion__item").forEach((t,s)=>{const n=e[s];if(!n)return;const i=this.isItemExpanded(n,s);t.classList.toggle("designbase-wc-accordion__item--expanded",i),t.classList.toggle("designbase-wc-accordion__item--disabled",Boolean(n.disabled));const a=t.querySelector(".designbase-wc-accordion__trigger"),d=t.querySelector(".designbase-wc-accordion__content");a?.setAttribute("aria-expanded",String(i)),d?.setAttribute("aria-hidden",String(!i))})}render(){this.isRendering=!0;const a=this.collectPanelContent(),d=s(this.getAttribute("variant"),n,"default"),r=s(this.getAttribute("size"),i,"m"),o=this.getExpandMode(),c=this.getAttribute("default-item-type")||"none",l=this.items,m=this.iconSize(r);this.className=["designbase-wc-accordion",`designbase-wc-accordion--${d}`,`designbase-wc-accordion--${r}`,"multiple"===o&&"designbase-wc-accordion--multiple","single"===o&&"designbase-wc-accordion--single","all"===o&&"designbase-wc-accordion--all"].filter(Boolean).join(" "),this.setAttribute("role","region"),this.setAttribute("aria-label",e("아코디언")),this.querySelectorAll(":scope > .designbase-wc-accordion__item").forEach(e=>e.remove()),l.forEach((e,s)=>{const n=this.resolveItemKey(e,s),i=this.isItemExpanded(e,s),r=document.createElement("div");r.className=["designbase-wc-accordion__item",`designbase-wc-accordion__item--${d}`,i&&"designbase-wc-accordion__item--expanded",e.disabled&&"designbase-wc-accordion__item--disabled"].filter(Boolean).join(" "),r.dataset.itemKey=n;const o=document.createElement("button");o.type="button",o.className="designbase-wc-accordion__trigger",o.disabled=Boolean(e.disabled),o.setAttribute("aria-expanded",String(i)),o.setAttribute("aria-controls",`accordion-content-${n}`),o.addEventListener("click",()=>{e.disabled||this.toggle(n)});const l=e.itemType||c;if("number"===l){const e=document.createElement("div");e.className="designbase-wc-accordion__number",e.textContent=`${s+1}.`,o.append(e)}else if("question"===l){const e=document.createElement("div");e.className="designbase-wc-accordion__question",e.textContent="Q.",o.append(e)}else if("icon"===l&&e.icon){const s=document.createElement("div");s.className="designbase-wc-accordion__icon",s.append(t(e.icon,m)),o.append(s)}const p=document.createElement("span");p.className="designbase-wc-accordion__title",p.textContent=e.title;const h=document.createElement("div");h.className="designbase-wc-accordion__chevron",h.append(t("chevron-down",m)),o.append(p,h);const u=document.createElement("div");u.id=`accordion-content-${n}`,u.className="designbase-wc-accordion__content",u.setAttribute("aria-hidden",String(!i));const b=document.createElement("div");b.className="designbase-wc-accordion__content-inner";const g=a.get(s)||[];if(g.length>0)g.forEach(e=>{e.removeAttribute("slot"),b.append(e)});else if(e.content){const t=document.createElement("p");t.className="designbase-wc-accordion__content-text",t.textContent=e.content,b.append(t)}u.append(b),r.append(o,u),this.append(r)}),this.isRendering=!1}toggle(e){const t=this.getExpandMode();this.expanded.has(e)?this.expanded.delete(e):"single"===t?this.expanded=new Set([e]):this.expanded.add(e);const s=Array.from(this.expanded);this.syncExpandedState(),this.suppressExpandedAttrCallback=!0,this.expandedItems=s,this.suppressExpandedAttrCallback=!1,this.dispatchEvent(new CustomEvent("db-change",{detail:{expandedItems:s},bubbles:!0,composed:!0}))}}customElements.get("db-accordion")||customElements.define("db-accordion",DbAccordion);export{DbAccordion};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{dbText as t}from"../core/i18n.js";import{DbElement as e}from"../core/base-element.js";import{textNode as i,replaceView as s}from"../core/credit-ui.js";import{createDbIcon as a}from"./db-icons.js";import"./db-button.js";function achievementItems(t){const e=new Set;return Array.isArray(t)?t.filter(t=>!(!t||"string"!=typeof t.id||!t.id||e.has(t.id)||"string"!=typeof t.title||"string"!=typeof t.description||!["locked","earned","needs_review"].includes(t.state))&&(e.add(t.id),!0)).map(t=>({id:t.id,title:t.title,description:t.description,state:t.state,current:Number.isSafeInteger(t.current)&&t.current>=0?t.current:void 0,target:Number.isSafeInteger(t.target)&&t.target>0?t.target:void 0,earnedLabel:"string"==typeof t.earnedLabel?t.earnedLabel:void 0,motif:["star","award","bulb","heart"].includes(t.motif||"")?t.motif:"award"})):[]}function achievementMedallion(t){const e=i("div","designbase-wc-achievement-art","");return e.dataset.state=t.state,e.setAttribute("aria-hidden","true"),e.append(a(t.motif||"award",40)),e}class DbAchievementList extends e{constructor(){super(...arguments),this.data=[]}static get observedAttributes(){return["label","empty-label","loading","error"]}get items(){return this.data.map(t=>({...t}))}set items(t){this.data=achievementItems(t),this.isConnected&&this.render()}connectedCallback(){this.upgradeProperties(["items"]),this.cleanups.listen(this,"db-click",t=>{const e=t.target instanceof HTMLElement?t.target.closest("[data-badge-id]"):null;e&&this.contains(e)&&!this.hasAttribute("loading")&&!this.hasAttribute("error")&&this.dbEmit("select",{id:e.dataset.badgeId})}),this.render()}attributeChangedCallback(){this.isConnected&&this.render()}render(){this.classList.add("designbase-wc-achievement-list"),this.setAttribute("aria-busy",String(this.hasAttribute("loading")));const e=i("div","designbase-wc-achievement-list__grid","");e.setAttribute("role","list"),e.setAttribute("aria-label",this.getAttribute("label")||"뱃지 목록");const a=this.getAttribute("error")||(this.hasAttribute("loading")?"뱃지를 불러오고 있어요":this.data.length?"":this.getAttribute("empty-label")||"아직 등록된 뱃지가 없어요");if(a){const t=i("p","designbase-wc-achievement-list__message",a);return t.setAttribute("role",this.hasAttribute("error")?"alert":"status"),void s(this,t)}for(const s of this.data){const a=i("article","designbase-wc-achievement-list__card","");if(a.dataset.state=s.state,a.setAttribute("role","listitem"),a.append(achievementMedallion(s),i("span","designbase-wc-achievement-list__state","earned"===s.state?"획득 완료":"needs_review"===s.state?"기록 확인 필요":"도전 중"),i("h3","",s.title),i("p","designbase-wc-achievement-list__description",s.description)),"locked"===s.state&&s.target){const t=document.createElement("progress");t.max=s.target,t.value=Math.min(s.current||0,s.target),t.setAttribute("aria-label",s.title+" 진행률"),a.append(t,i("span","designbase-wc-achievement-list__date",`${Math.min(s.current||0,s.target)} / ${s.target}`))}else a.append(i("span","designbase-wc-achievement-list__date","earned"===s.state?s.earnedLabel||"나의 컬렉션에 담았어요":"needs_review"===s.state?"연결된 기록을 다시 확인해 주세요":"다음 순간을 기다려요"));const r=document.createElement("db-button");r.setAttribute("variant","secondary"),r.setAttribute("size","s"),r.dataset.badgeId=s.id,r.dataset.action=s.id,r.textContent=t("자세히 보기"),r.setAttribute("aria-label",s.title+" 자세히 보기"),a.append(r),e.append(a)}s(this,e)}}customElements.get("db-achievement-list")||customElements.define("db-achievement-list",DbAchievementList);export{DbAchievementList,achievementItems,achievementMedallion};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{dbText as t}from"../core/i18n.js";import{DbElement as e}from"../core/base-element.js";import{textNode as i,creditAction as s,replaceView as a}from"../core/credit-ui.js";import{dbUid as n}from"../core/uid.js";import{achievementItems as o,achievementMedallion as d}from"./db-achievement-list.js";import"./db-modal.js";import"./db-confetti.js";import"./db-button.js";class DbAchievementModal extends e{constructor(){super(...arguments),this.data=[],this.frame=null,this.viewKey="",this.presentationKey="",this.descriptionId=n("achievement-description"),this.headingId=n("achievement-heading")}static get observedAttributes(){return["open","mode","loading","error","confirm-label"]}get items(){return this.data.map(t=>({...t}))}set items(t){this.data=o(t),this.isConnected&&this.sync()}get open(){return this.hasAttribute("open")&&"false"!==this.getAttribute("open")}set open(t){this.toggleAttribute("open",t)}connectedCallback(){this.upgradeProperties(["items","open"]),this.ensureView(),this.cleanups.listen(this.modal,"db-close",t=>{t.stopPropagation(),this.dismiss(),queueMicrotask(()=>{this.isConnected&&this.open&&this.modal&&!this.modal.open&&(this.modal.open=!0)})}),this.cleanups.listen(this.body,"db-click",t=>{t.target instanceof HTMLElement&&["acknowledge","dismiss"].includes(t.target.dataset.action||"")&&this.dismiss()}),this.cleanups.listen(window.matchMedia("(prefers-reduced-motion: reduce)"),"change",()=>{this.stopEffects(),this.viewKey="",this.sync()}),this.sync()}disconnectedCallback(){this.stopEffects(),this.modal?.remove(),this.modal=void 0,this.viewKey="",this.presentationKey="",super.disconnectedCallback()}attributeChangedCallback(){this.isConnected&&this.sync()}dismiss(){!this.hasAttribute("loading")&&this.open&&this.dbEmit("dismiss",{ids:this.data.map(t=>t.id)})}stopEffects(){null!==this.frame&&cancelAnimationFrame(this.frame),this.frame=null,this.confetti?.remove(),this.confetti=void 0}ensureView(){this.modal||(this.modal=document.createElement("db-modal"),this.modal.setAttribute("size","s"),this.body=i("div","designbase-wc-achievement-modal__body",""),this.body.setAttribute("data-modal-part","body"),this.modal.append(this.body),this.append(this.modal))}stage(t){const e=i("div","designbase-wc-achievement-modal__stage","");e.setAttribute("aria-hidden","true"),this.open&&"earned"===t.state&&!window.matchMedia("(prefers-reduced-motion: reduce)").matches&&(this.confetti=document.createElement("db-confetti"),this.confetti.setAttribute("trigger","manual"),e.append(this.confetti));const s=i("div","designbase-wc-achievement-modal__coin","");s.dataset.state=t.state;for(let t=-5;t<=5;t++){const e=i("span","designbase-wc-achievement-modal__edge","");e.style.transform=`translateZ(${t}px)`,s.append(e)}const a=d(t);a.classList.add("designbase-wc-achievement-modal__face","designbase-wc-achievement-modal__face--front");const n=d(t);return n.classList.add("designbase-wc-achievement-modal__face","designbase-wc-achievement-modal__face--back"),s.append(a,n),e.append(s),e}sync(){if(!this.modal||!this.body)return;const e=this.data[0],n="detail"!==this.getAttribute("mode");this.modal.removeAttribute("title"),this.modal.setAttribute("describedby",this.descriptionId),this.modal.setAttribute("show-close-button","false");for(const t of["close-on-escape","close-on-outside-click"])this.modal.setAttribute(t,String(!this.hasAttribute("loading")));const o=JSON.stringify([this.data,n,this.open,this.hasAttribute("loading"),this.getAttribute("error"),this.getAttribute("confirm-label")]);if(o!==this.viewKey){this.viewKey=o,this.stopEffects();const d=document.createElement("div"),c=s("dismiss","",this.hasAttribute("loading"));if(c.classList.add("designbase-wc-achievement-modal__close"),c.setAttribute("variant","ghost"),c.setAttribute("start-icon","close"),c.setAttribute("icon-only",""),c.setAttribute("aria-label",t("모달 닫기")),d.append(c),e){d.append(this.stage(e),i("span","designbase-wc-achievement-modal__eyebrow","locked"===e.state?"아직 획득하지 못한 뱃지":"needs_review"===e.state?"기록 확인 필요":n?"새로운 순간을 모았어요":"나의 컬렉션"));const t=i("h3","",e.title);t.id=this.headingId,d.append(t);const s=i("p","designbase-wc-achievement-modal__description",e.description);if(s.id=this.descriptionId,d.append(s),e.earnedLabel&&"earned"===e.state&&d.append(i("p","designbase-wc-achievement-list__date",e.earnedLabel)),this.data.length>1){const t=i("div","designbase-wc-achievement-modal__related","함께 받은 뱃지 "+(this.data.length-1)+"개");for(const e of this.data.slice(1))t.append(i("span","",e.title));d.append(t)}}else{const t=i("p","","표시할 뱃지가 없어요");t.id=this.descriptionId,d.append(t)}const r=i("p","designbase-wc-achievement-modal__error",this.getAttribute("error")||"");r.setAttribute("role","alert"),r.hidden=!r.textContent,d.append(r);const h=this.getAttribute("confirm-label")||("locked"===e?.state?"아직 획득하지 못했어요":"확인"),l=s("acknowledge",h,this.hasAttribute("loading"));l.setAttribute("variant","locked"===e?.state?"secondary":"primary"),l.setAttribute("size","m"),l.toggleAttribute("loading",this.hasAttribute("loading")),d.append(l),a(this.body,...Array.from(d.childNodes))}this.modal.open!==this.open&&(this.modal.open=this.open);const d=this.body.closest('[role="dialog"]');d?.classList.add("designbase-wc-achievement-modal__panel"),e&&d?.setAttribute("aria-labelledby",this.headingId);const c=JSON.stringify([this.data.map(t=>[t.id,t.state]),n]);this.open?this.presentationKey!==c&&(this.presentationKey=c,this.frame=requestAnimationFrame(()=>{if(this.frame=null,this.open&&this.isConnected&&this.confetti)for(const[t,e]of[[.08,65],[.92,115]])this.confetti.fire({particleCount:42,origin:{x:t,y:.88},angle:e,spread:75,startVelocity:26,ticks:140,scalar:.75,disableForReducedMotion:!0})})):(this.presentationKey="",this.stopEffects())}}customElements.get("db-achievement-modal")||customElements.define("db-achievement-modal",DbAchievementModal);export{DbAchievementModal};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{dbText as e,getDbLocale as t}from"../core/i18n.js";import{sanitizeHref as a}from"../core/safe-url.js";import{ACTIVITY_HEATMAP_SIZES as s,ACTIVITY_HEATMAP_COLOR_SCHEMES as n}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const r="designbase-wc-activity-heatmap";class DbActivityHeatmap extends HTMLElement{constructor(){super(...arguments),this.handleClick=e=>{const t=e.target,a=t?.closest(`.${r}__cell`);if(!a||a.disabled)return;const s=a.dataset.date;if(!s)return;const n=Number(a.dataset.value??"0"),l=Number(a.dataset.level??"0");this.dispatchEvent(new CustomEvent("db-cell-click",{detail:{date:s,value:n,level:l},bubbles:!0,composed:!0}))}}static get observedAttributes(){return["data","end-date","weeks","week-starts-on","size","locale","color-scheme","show-legend","show-month-labels","show-day-labels","legend-less-label","legend-more-label","value-label","max-value","footer-text","footer-href"]}connectedCallback(){this.addEventListener("click",this.handleClick),this.render()}disconnectedCallback(){this.removeEventListener("click",this.handleClick)}attributeChangedCallback(){this.render()}parseData(){const e=this.getAttribute("data");if(!e)return[];try{const t=JSON.parse(e);return Array.isArray(t)?t.filter(e=>e&&"string"==typeof e.date&&"number"==typeof e.value):[]}catch{return[]}}parseEndDate(){const e=this.getAttribute("end-date");if(e){const t=this.parseISODate(e);if(t)return t}const t=new Date;return new Date(t.getFullYear(),t.getMonth(),t.getDate())}parseISODate(e){const t=/^(\d{4})-(\d{2})-(\d{2})/.exec(e.trim());if(!t)return null;const a=Number(t[1]),s=Number(t[2]),n=Number(t[3]);return a&&s&&n?new Date(a,s-1,n):null}formatISODate(e){return`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,"0")}-${String(e.getDate()).padStart(2,"0")}`}addDays(e,t){const a=new Date(e);return a.setDate(a.getDate()+t),a}startOfWeek(e,t){const a=(e.getDay()-t+7)%7;return this.addDays(e,-a)}isAfter(e,t){return e.getTime()>t.getTime()}buildWeeks(e,t,a){const s=this.startOfWeek(e,a),n=this.addDays(s,7*-(t-1)),r=[];for(let e=0;e<t;e+=1){const t=[];for(let a=0;a<7;a+=1)t.push(this.addDays(n,7*e+a));r.push(t)}return r}resolveLevel(e,t,a){if(e<=0||t<=0)return 0;const s=e/t;return Math.min(a,Math.max(1,Math.ceil(s*a)))}formatMonthLabel(e,t){return new Intl.DateTimeFormat(t,{month:"short"}).format(e)}formatTooltip(e,t,a,s){const n=new Intl.DateTimeFormat(a,{year:"numeric",month:"long",day:"numeric"}).format(e);return t<=0?`${n}: 활동 없음`:`${n}: ${t.toLocaleString(a)}${s}`}getDayLabels(e,t){const a=Array.from({length:7},(a,s)=>{const n=new Date(2024,0,7+(e+s)%7);return new Intl.DateTimeFormat(t,{weekday:"short"}).format(n)}),s=1===e?[0,2,4,6]:[1,3,5,0];return a.map((e,t)=>s.includes(t)?e:"")}getMonthLabels(e,t){const a=e.map(e=>{const t=e.find(e=>e.getDate()<=7)??e[0];return t.getMonth()+12*t.getFullYear()}),s=e.map(()=>"");let n=0;for(;n<e.length;){const r=a[n];let l=n+1;for(;l<e.length&&a[l]===r;)l+=1;if(l-n>=2){const a=e[n],r=a.find(e=>e.getDate()<=7)??a[0];s[n]=this.formatMonthLabel(r,t)}n=l}return s}render(){const l=this.parseData(),o=new Map(l.map(e=>[e.date,e.value])),i=this.parseEndDate(),c=Math.max(1,Number(this.getAttribute("weeks")??"53")||53),d="0"===this.getAttribute("week-starts-on")?0:1,m=this.getAttribute("size")||"m",u=s.includes(m)?m:"m",h=this.getAttribute("locale")||("ko"===t()?"ko-KR":"en-US"),p=this.getAttribute("color-scheme")||"green",b=n.includes(p)?p:"green",g="false"!==this.getAttribute("show-legend"),f="false"!==this.getAttribute("show-month-labels"),_="false"!==this.getAttribute("show-day-labels"),v=this.getAttribute("legend-less-label")||"적음",$=this.getAttribute("legend-more-label")||"많음",E=this.getAttribute("value-label")||"회",A=this.getAttribute("footer-text")||"",D=this.getAttribute("footer-href")||"",y=this.getAttribute("max-value"),N=l.map(e=>e.value).filter(e=>e>0),k=N.length?Math.max(...N):0,w=y?Math.max(Number(y)||0,k):k,x=this.buildWeeks(i,c,d),C=this.getMonthLabels(x,h),M=this.getDayLabels(d,h);this.className=[r,`${r}--size-${u}`,`${r}--color-${b}`,g&&`${r}--with-legend`].filter(Boolean).join(" "),this.replaceChildren();const L=document.createElement("div");L.className=`${r}__viewport`;const S=document.createElement("div");if(S.className=`${r}__scroll-inner`,_){const e=document.createElement("div");e.className=`${r}__sticky-rail`;const t=document.createElement("div");t.className=`${r}__sticky-spacer`,f||t.classList.add(`${r}__sticky-spacer--hidden`);const a=document.createElement("div");a.className=`${r}__days`,a.setAttribute("aria-hidden","true"),M.forEach(e=>{const t=document.createElement("span");t.className=`${r}__day`,t.textContent=e,a.append(t)}),e.append(t,a),S.append(e)}const T=document.createElement("div");if(T.className=`${r}__grid-area`,f){const e=document.createElement("div");e.className=`${r}__months`,e.setAttribute("aria-hidden","true"),C.forEach(t=>{const a=document.createElement("span");a.className=`${r}__month`,a.textContent=t,e.append(a)}),T.append(e)}const I=document.createElement("div");if(I.className=`${r}__weeks`,I.setAttribute("role","grid"),I.setAttribute("aria-label",e("활동 히트맵")),x.forEach(e=>{const t=document.createElement("div");t.className=`${r}__week`,t.setAttribute("role","row"),e.forEach(e=>{const a=this.formatISODate(e),s=this.isAfter(e,i),n=s?0:o.get(a)??0,l=s?0:this.resolveLevel(n,w,4),c=document.createElement("button");c.type="button",c.className=[`${r}__cell`,`${r}__cell--level-${l}`,s&&`${r}__cell--future`].filter(Boolean).join(" "),c.dataset.date=a,c.dataset.value=String(n),c.dataset.level=String(l),c.title=this.formatTooltip(e,n,h,E),c.setAttribute("aria-label",this.formatTooltip(e,n,h,E)),c.disabled=s,t.append(c)}),I.append(t)}),T.append(I),S.append(T),L.append(S),this.append(L),g||A){const e=document.createElement("div");if(e.className=`${r}__footer`,A)if(D){const t=document.createElement("a");t.className=`${r}__footer-link`,t.href=a(D,"#"),t.textContent=A,e.append(t)}else{const t=document.createElement("span");t.className=`${r}__footer-text`,t.textContent=A,e.append(t)}else e.append(document.createElement("span"));if(g){const t=document.createElement("div");t.className=`${r}__legend`,t.setAttribute("aria-hidden","true");const a=document.createElement("span");a.className=`${r}__legend-label`,a.textContent=v;const s=document.createElement("div");s.className=`${r}__legend-scale`;for(let e=0;e<=4;e+=1){const t=document.createElement("span");t.className=`${r}__legend-cell ${r}__legend-cell--level-${e}`,s.append(t)}const n=document.createElement("span");n.className=`${r}__legend-label`,n.textContent=$,t.append(a,s,n),e.append(t)}this.append(e)}}}customElements.get("db-activity-heatmap")||customElements.define("db-activity-heatmap",DbActivityHeatmap);export{DbActivityHeatmap};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createDbIcon as t}from"./db-icons.js";import{sanitizeHref as e}from"../core/safe-url.js";import{coerceToContract as i}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{AD_BANNER_VARIANTS as s,AD_BANNER_SIZES as n}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const r="designbase-wc-ad-banner",a={hero:"지금 바로 시작하세요",topbar:"🎉 신규 가입 시 10,000원 적립금 증정!",card:"프리미엄 멤버십",floating:"오늘만 특가!"},l={hero:"최대 50% 할인된 가격으로 프리미엄 서비스를 경험해보세요. 기간 한정 특별 혜택!",topbar:"오늘 하루만 특별 혜택",card:"무제한 서비스 이용권을 특별가에 만나보세요",floating:"장바구니에 담긴 상품 추가 20% 할인"},o={hero:"자세히 보기",topbar:"지금 가입하기",card:"알아보기",floating:"할인받기"},h="star-filled",d={primary:"primary",secondary:"secondary",success:"success",warning:"warning",error:"error"};class DbAdBanner extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.visible=!0,this.progress=100}static get observedAttributes(){return["type","variant","size","title","subtitle","cta-text","image","image-alt","href","target","auto-close","close-delay","background","animation-type","grid-type","use-random-gradient","gradient-scheme","gradient-tone","gradient-animated","countdown-end-date","show-countdown","open"]}connectedCallback(){this.style.display="block",this.built||(this.built=!0,this.build()),this.updateUI()}disconnectedCallback(){this.stopAutoClose()}attributeChangedCallback(t){this.built&&("open"===t&&(this.visible="false"!==this.getAttribute("open")),this.updateUI())}getBool(t,e=!1){if(!this.hasAttribute(t))return e;const i=this.getAttribute(t);return""===i||"true"===i}getType(){const t=this.getAttribute("type")||"hero";return["hero","topbar","card","floating"].includes(t)?t:"hero"}getVariant(){return i(this.getAttribute("variant"),s,"primary")}getSize(){return i(this.getAttribute("size"),n,"m")}ctaButtonSize(t,e){return"card"===t?"s":"floating"===t?"s"===e?"s":"m":e}build(){this.rootEl=document.createElement("div"),this.contentEl=document.createElement("div"),this.contentEl.className=`${r}__content`,this.closeBtn=document.createElement("button"),this.closeBtn.type="button",this.closeBtn.className=`${r}__close`,this.closeBtn.setAttribute("aria-label","닫기"),this.closeBtn.append(t("close",16)),this.closeBtn.addEventListener("click",t=>{t.stopPropagation(),this.handleClose()}),this.imageEl=document.createElement("img"),this.imageEl.className=`${r}__image`,this.imageEl.loading="lazy";const e=document.createElement("div");e.className=`${r}__main`,this.mainEl=e,this.iconEl=document.createElement("div"),this.iconEl.className=`${r}__icon`,this.labelEl=document.createElement("span"),this.labelEl.className=`${r}__label`,this.labelEl.textContent="특별 이벤트",this.badgeEl=document.createElement("span"),this.badgeEl.className=`${r}__badge`,this.badgeEl.textContent="HOT DEAL",this.titleEl=document.createElement("h2"),this.titleEl.className=`${r}__title`,this.subtitleEl=document.createElement("p"),this.subtitleEl.className=`${r}__subtitle`;const i=document.createElement("div");i.className=`${r}__text`,this.textEl=i,this.countdownWrapEl=document.createElement("div"),this.countdownWrapEl.className=`${r}__countdown`,i.append(this.titleEl,this.subtitleEl),this.actionsEl=document.createElement("div"),this.actionsEl.className=`${r}__actions`,this.ctaEl=document.createElement("db-button"),this.ctaEl.className=`${r}__cta`,this.ctaEl.setAttribute("variant","primary"),this.ctaEl.setAttribute("end-icon","arrow-right"),this.ctaEl.addEventListener("click",t=>{t.stopPropagation(),this.dispatchEvent(new CustomEvent("db-cta-click",{bubbles:!0,composed:!0}))}),this.actionsEl.append(this.ctaEl),e.append(i,this.actionsEl),this.progressEl=document.createElement("div"),this.progressEl.className=`${r}__progress`,this.progressBarEl=document.createElement("div"),this.progressBarEl.className=`${r}__progress-bar`,this.progressEl.append(this.progressBarEl),this.contentEl.append(this.closeBtn,e,this.progressEl),this.rootEl.append(this.contentEl),this.append(this.rootEl),this.contentEl.addEventListener("click",t=>{"topbar"===this.getType()&&(t.target?.closest(`.${r}__close`)||this.dispatchEvent(new CustomEvent("db-cta-click",{bubbles:!0,composed:!0})))})}handleClose(){this.visible=!1,this.style.display="none",this.setAttribute("open","false"),this.stopAutoClose(),this.dispatchEvent(new CustomEvent("db-close",{bubbles:!0,composed:!0}))}stopAutoClose(){this.autoCloseTimer&&(window.clearInterval(this.autoCloseTimer),this.autoCloseTimer=void 0)}startAutoClose(t){this.stopAutoClose(),this.progress=100,this.autoCloseTimer=window.setInterval(()=>{this.progress-=100/(t/100),this.progressBarEl&&(this.progressBarEl.style.width=`${Math.max(this.progress,0)}%`),this.progress<=0&&this.handleClose()},100)}getBackground(){const t=this.getAttribute("background");return t&&["solid","gradient","animation","grid"].includes(t)?t:this.getBool("use-random-gradient")?"gradient":"solid"}ensureAnimBg(){if(!this.animBgEl){const t=document.createElement("div");t.className=`${r}__backdrop`;const e=document.createElement("db-animation-background");e.className=`${r}__anim-bg`,e.setAttribute("width","100%"),e.setAttribute("height","100%"),t.append(e),this.animBgEl=t,this.animBgInner=e}return this.animBgEl}ensureGridBg(){if(!this.gridBgEl){const t=document.createElement("div");t.className=`${r}__backdrop`;const e=document.createElement("db-grid-background");e.className=`${r}__grid-bg`,e.setAttribute("width","100%"),e.setAttribute("height","100%"),t.append(e),this.gridBgEl=t,this.gridBgInner=e}return this.gridBgEl}clearBackdrop(t){"gradient"!==t&&this.gradientEl&&(this.gradientEl.remove(),this.gradientEl=void 0),"animation"!==t&&this.animBgEl&&(this.animBgEl.remove(),this.animBgEl=void 0,this.animBgInner=void 0),"grid"!==t&&this.gridBgEl&&(this.gridBgEl.remove(),this.gridBgEl=void 0,this.gridBgInner=void 0)}renderBackground(t,e){if(!this.rootEl||!this.contentEl)return;if(this.clearBackdrop(t),"gradient"===t){this.gradientEl||(this.gradientEl=document.createElement("db-random-gradient"),this.gradientEl.className=`${r}__gradient-bg`,this.gradientEl.setAttribute("height","100%"),this.gradientEl.setAttribute("width","100%"));const t=this.getAttribute("gradient-tone")||"vivid",i=!this.hasAttribute("gradient-animated")||"false"!==this.getAttribute("gradient-animated");return this.gradientEl.setAttribute("scheme",this.getAttribute("gradient-scheme")||d[e]),this.gradientEl.setAttribute("tone",t),this.gradientEl.setAttribute("animated",i?"true":"false"),this.gradientEl.parentElement!==this.rootEl&&this.rootEl.replaceChildren(this.gradientEl),void(this.contentEl.parentElement!==this.gradientEl&&this.gradientEl.append(this.contentEl))}const i=[];if("animation"===t){const t=this.ensureAnimBg();this.animBgInner?.setAttribute("type",this.getAttribute("animation-type")||"graphite"),this.animBgInner?.setAttribute("theme","dark"),i.push(t)}else if("grid"===t){const t=this.ensureGridBg();this.gridBgInner?.setAttribute("type",this.getAttribute("grid-type")||"lines"),this.gridBgInner?.setAttribute("color","var(--db-text-inverse-primary)"),this.gridBgInner?.setAttribute("opacity","0.18"),this.gridBgInner?.setAttribute("fade","vignette"),this.gridBgInner?.setAttribute("animated",""),i.push(t)}const s=[...i,this.contentEl],n=Array.from(this.rootEl.children);n.length===s.length&&s.every((t,e)=>n[e]===t)||this.rootEl.replaceChildren(...s)}syncIcon(e){this.mainEl&&this.textEl&&this.iconEl&&("card"===e?(this.iconEl.replaceChildren(t(h,32)),this.iconEl.parentElement!==this.mainEl&&this.mainEl.insertBefore(this.iconEl,this.textEl)):this.iconEl.remove())}syncBadge(t){this.textEl&&this.badgeEl&&("floating"===t?this.badgeEl.parentElement!==this.textEl&&this.textEl.insertBefore(this.badgeEl,this.textEl.firstChild):this.badgeEl.remove())}syncImage(t,e){this.contentEl&&this.imageEl&&this.mainEl&&("floating"===t&&e?(this.imageEl.src=e,this.imageEl.alt=this.getAttribute("image-alt")||"",this.imageEl.parentElement!==this.contentEl&&this.contentEl.insertBefore(this.imageEl,this.mainEl)):this.imageEl.remove())}syncLink(t,i){if(!this.contentEl)return;const s=e(i,"");if("topbar"!==t||!s)return void this.linkEl?.remove();this.linkEl||(this.linkEl=document.createElement("a"),this.linkEl.className=`${r}__link`),this.linkEl.setAttribute("href",s);const n=this.getAttribute("target");n?this.linkEl.setAttribute("target",n):this.linkEl.removeAttribute("target"),this.linkEl.setAttribute("aria-label",this.titleEl?.textContent||"배너 링크"),this.linkEl.parentElement!==this.contentEl&&this.contentEl.append(this.linkEl)}syncCountdown(t,e){this.textEl&&this.countdownWrapEl&&(t&&e?(this.countdownEl||(this.countdownEl=document.createElement("db-countdown"),this.countdownEl.setAttribute("size","s"),this.countdownEl.setAttribute("variant","compact"),this.countdownEl.setAttribute("show-labels","false"),this.countdownWrapEl.replaceChildren(this.countdownEl)),this.countdownEl.setAttribute("end-date",e),this.countdownWrapEl.parentElement!==this.textEl&&this.textEl.append(this.countdownWrapEl)):this.countdownWrapEl.remove())}updateUI(){if(!this.visible||"false"===this.getAttribute("open"))return void(this.style.display="none");this.style.display="block";const t=this.getType(),e=this.getVariant(),i=this.getSize(),s=this.getAttribute("title")||a[t],n=this.getAttribute("subtitle")||l[t],h=this.getAttribute("cta-text")||o[t],d=this.getBool("auto-close"),c=Math.max(Number(this.getAttribute("close-delay")||5e3),1e3),g=this.getBackground(),E=this.getAttribute("gradient-tone")||"vivid",u=this.getBool("show-countdown"),m=this.getAttribute("countdown-end-date");this.rootEl&&(this.rootEl.className=[r,`${r}--type-${t}`,`${r}--variant-${e}`,`${r}--size-${i}`,`${r}--bg-${g}`,d&&`${r}--auto-close`,"gradient"===g&&`${r}--with-gradient`,"gradient"===g&&"light"===E&&`${r}--gradient-light`].filter(Boolean).join(" ")),this.renderBackground(g,e),this.syncIcon(t),this.syncBadge(t),this.syncImage(t,this.getAttribute("image")),this.syncLink(t,this.getAttribute("href")),this.titleEl&&(this.titleEl.textContent=s),this.subtitleEl&&(this.subtitleEl.textContent=n),this.syncCountdown(u,m),this.actionsEl&&(this.actionsEl.hidden="topbar"===t),this.ctaEl&&(this.ctaEl.textContent=h,this.ctaEl.setAttribute("size",this.ctaButtonSize(t,i)),"floating"===t?this.ctaEl.setAttribute("full-width",""):this.ctaEl.removeAttribute("full-width")),this.progressEl&&(this.progressEl.hidden=!d),this.progressBarEl&&d&&(this.progressBarEl.style.width=`${this.progress}%`),this.stopAutoClose(),d&&this.startAutoClose(c)}}customElements.get("db-ad-banner")||customElements.define("db-ad-banner",DbAdBanner);export{DbAdBanner};
|
|
1
|
+
import{dbText as t}from"../core/i18n.js";import{createDbIcon as e}from"./db-icons.js";import{sanitizeHref as i}from"../core/safe-url.js";import{coerceToContract as s}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{AD_BANNER_VARIANTS as n,AD_BANNER_SIZES as r}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const a="designbase-wc-ad-banner",l={hero:"지금 바로 시작하세요",topbar:"🎉 신규 가입 시 10,000원 적립금 증정!",card:"프리미엄 멤버십",floating:"오늘만 특가!"},o={hero:"최대 50% 할인된 가격으로 프리미엄 서비스를 경험해보세요. 기간 한정 특별 혜택!",topbar:"오늘 하루만 특별 혜택",card:"무제한 서비스 이용권을 특별가에 만나보세요",floating:"장바구니에 담긴 상품 추가 20% 할인"},h={hero:"자세히 보기",topbar:"지금 가입하기",card:"알아보기",floating:"할인받기"},d="star-filled",c={primary:"primary",secondary:"secondary",success:"success",warning:"warning",error:"error"};class DbAdBanner extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.visible=!0,this.progress=100}static get observedAttributes(){return["type","variant","size","title","subtitle","cta-text","image","image-alt","href","target","auto-close","close-delay","background","animation-type","grid-type","use-random-gradient","gradient-scheme","gradient-tone","gradient-animated","countdown-end-date","show-countdown","open"]}connectedCallback(){this.style.display="block",this.built||(this.built=!0,this.build()),this.updateUI()}disconnectedCallback(){this.stopAutoClose()}attributeChangedCallback(t){this.built&&("open"===t&&(this.visible="false"!==this.getAttribute("open")),this.updateUI())}getBool(t,e=!1){if(!this.hasAttribute(t))return e;const i=this.getAttribute(t);return""===i||"true"===i}getType(){const t=this.getAttribute("type")||"hero";return["hero","topbar","card","floating"].includes(t)?t:"hero"}getVariant(){return s(this.getAttribute("variant"),n,"primary")}getSize(){return s(this.getAttribute("size"),r,"m")}ctaButtonSize(t,e){return"card"===t?"s":"floating"===t?"s"===e?"s":"m":e}build(){this.rootEl=document.createElement("div"),this.contentEl=document.createElement("div"),this.contentEl.className=`${a}__content`,this.closeBtn=document.createElement("button"),this.closeBtn.type="button",this.closeBtn.className=`${a}__close`,this.closeBtn.setAttribute("aria-label",t("닫기")),this.closeBtn.append(e("close",16)),this.closeBtn.addEventListener("click",t=>{t.stopPropagation(),this.handleClose()}),this.imageEl=document.createElement("img"),this.imageEl.className=`${a}__image`,this.imageEl.loading="lazy";const i=document.createElement("div");i.className=`${a}__main`,this.mainEl=i,this.iconEl=document.createElement("div"),this.iconEl.className=`${a}__icon`,this.labelEl=document.createElement("span"),this.labelEl.className=`${a}__label`,this.labelEl.textContent=t("특별 이벤트"),this.badgeEl=document.createElement("span"),this.badgeEl.className=`${a}__badge`,this.badgeEl.textContent="HOT DEAL",this.titleEl=document.createElement("h2"),this.titleEl.className=`${a}__title`,this.subtitleEl=document.createElement("p"),this.subtitleEl.className=`${a}__subtitle`;const s=document.createElement("div");s.className=`${a}__text`,this.textEl=s,this.countdownWrapEl=document.createElement("div"),this.countdownWrapEl.className=`${a}__countdown`,s.append(this.titleEl,this.subtitleEl),this.actionsEl=document.createElement("div"),this.actionsEl.className=`${a}__actions`,this.ctaEl=document.createElement("db-button"),this.ctaEl.className=`${a}__cta`,this.ctaEl.setAttribute("variant","primary"),this.ctaEl.setAttribute("end-icon","arrow-right"),this.ctaEl.addEventListener("click",t=>{t.stopPropagation(),this.dispatchEvent(new CustomEvent("db-cta-click",{bubbles:!0,composed:!0}))}),this.actionsEl.append(this.ctaEl),i.append(s,this.actionsEl),this.progressEl=document.createElement("div"),this.progressEl.className=`${a}__progress`,this.progressBarEl=document.createElement("div"),this.progressBarEl.className=`${a}__progress-bar`,this.progressEl.append(this.progressBarEl),this.contentEl.append(this.closeBtn,i,this.progressEl),this.rootEl.append(this.contentEl),this.append(this.rootEl),this.contentEl.addEventListener("click",t=>{"topbar"===this.getType()&&(t.target?.closest(`.${a}__close`)||this.dispatchEvent(new CustomEvent("db-cta-click",{bubbles:!0,composed:!0})))})}handleClose(){this.visible=!1,this.style.display="none",this.setAttribute("open","false"),this.stopAutoClose(),this.dispatchEvent(new CustomEvent("db-close",{bubbles:!0,composed:!0}))}stopAutoClose(){this.autoCloseTimer&&(window.clearInterval(this.autoCloseTimer),this.autoCloseTimer=void 0)}startAutoClose(t){this.stopAutoClose(),this.progress=100,this.autoCloseTimer=window.setInterval(()=>{this.progress-=100/(t/100),this.progressBarEl&&(this.progressBarEl.style.width=`${Math.max(this.progress,0)}%`),this.progress<=0&&this.handleClose()},100)}getBackground(){const t=this.getAttribute("background");return t&&["solid","gradient","animation","grid"].includes(t)?t:this.getBool("use-random-gradient")?"gradient":"solid"}ensureAnimBg(){if(!this.animBgEl){const t=document.createElement("div");t.className=`${a}__backdrop`;const e=document.createElement("db-animation-background");e.className=`${a}__anim-bg`,e.setAttribute("width","100%"),e.setAttribute("height","100%"),t.append(e),this.animBgEl=t,this.animBgInner=e}return this.animBgEl}ensureGridBg(){if(!this.gridBgEl){const t=document.createElement("div");t.className=`${a}__backdrop`;const e=document.createElement("db-grid-background");e.className=`${a}__grid-bg`,e.setAttribute("width","100%"),e.setAttribute("height","100%"),t.append(e),this.gridBgEl=t,this.gridBgInner=e}return this.gridBgEl}clearBackdrop(t){"gradient"!==t&&this.gradientEl&&(this.gradientEl.remove(),this.gradientEl=void 0),"animation"!==t&&this.animBgEl&&(this.animBgEl.remove(),this.animBgEl=void 0,this.animBgInner=void 0),"grid"!==t&&this.gridBgEl&&(this.gridBgEl.remove(),this.gridBgEl=void 0,this.gridBgInner=void 0)}renderBackground(t,e){if(!this.rootEl||!this.contentEl)return;if(this.clearBackdrop(t),"gradient"===t){this.gradientEl||(this.gradientEl=document.createElement("db-random-gradient"),this.gradientEl.className=`${a}__gradient-bg`,this.gradientEl.setAttribute("height","100%"),this.gradientEl.setAttribute("width","100%"));const t=this.getAttribute("gradient-tone")||"vivid",i=!this.hasAttribute("gradient-animated")||"false"!==this.getAttribute("gradient-animated");return this.gradientEl.setAttribute("scheme",this.getAttribute("gradient-scheme")||c[e]),this.gradientEl.setAttribute("tone",t),this.gradientEl.setAttribute("animated",i?"true":"false"),this.gradientEl.parentElement!==this.rootEl&&this.rootEl.replaceChildren(this.gradientEl),void(this.contentEl.parentElement!==this.gradientEl&&this.gradientEl.append(this.contentEl))}const i=[];if("animation"===t){const t=this.ensureAnimBg();this.animBgInner?.setAttribute("type",this.getAttribute("animation-type")||"graphite"),this.animBgInner?.setAttribute("theme","dark"),i.push(t)}else if("grid"===t){const t=this.ensureGridBg();this.gridBgInner?.setAttribute("type",this.getAttribute("grid-type")||"lines"),this.gridBgInner?.setAttribute("color","var(--db-text-inverse-primary)"),this.gridBgInner?.setAttribute("opacity","0.18"),this.gridBgInner?.setAttribute("fade","vignette"),this.gridBgInner?.setAttribute("animated",""),i.push(t)}const s=[...i,this.contentEl],n=Array.from(this.rootEl.children);n.length===s.length&&s.every((t,e)=>n[e]===t)||this.rootEl.replaceChildren(...s)}syncIcon(t){this.mainEl&&this.textEl&&this.iconEl&&("card"===t?(this.iconEl.replaceChildren(e(d,32)),this.iconEl.parentElement!==this.mainEl&&this.mainEl.insertBefore(this.iconEl,this.textEl)):this.iconEl.remove())}syncBadge(t){this.textEl&&this.badgeEl&&("floating"===t?this.badgeEl.parentElement!==this.textEl&&this.textEl.insertBefore(this.badgeEl,this.textEl.firstChild):this.badgeEl.remove())}syncImage(t,e){this.contentEl&&this.imageEl&&this.mainEl&&("floating"===t&&e?(this.imageEl.src=e,this.imageEl.alt=this.getAttribute("image-alt")||"",this.imageEl.parentElement!==this.contentEl&&this.contentEl.insertBefore(this.imageEl,this.mainEl)):this.imageEl.remove())}syncLink(t,e){if(!this.contentEl)return;const s=i(e,"");if("topbar"!==t||!s)return void this.linkEl?.remove();this.linkEl||(this.linkEl=document.createElement("a"),this.linkEl.className=`${a}__link`),this.linkEl.setAttribute("href",s);const n=this.getAttribute("target");n?this.linkEl.setAttribute("target",n):this.linkEl.removeAttribute("target"),this.linkEl.setAttribute("aria-label",this.titleEl?.textContent||"배너 링크"),this.linkEl.parentElement!==this.contentEl&&this.contentEl.append(this.linkEl)}syncCountdown(t,e){this.textEl&&this.countdownWrapEl&&(t&&e?(this.countdownEl||(this.countdownEl=document.createElement("db-countdown"),this.countdownEl.setAttribute("size","s"),this.countdownEl.setAttribute("variant","compact"),this.countdownEl.setAttribute("show-labels","false"),this.countdownWrapEl.replaceChildren(this.countdownEl)),this.countdownEl.setAttribute("end-date",e),this.countdownWrapEl.parentElement!==this.textEl&&this.textEl.append(this.countdownWrapEl)):this.countdownWrapEl.remove())}updateUI(){if(!this.visible||"false"===this.getAttribute("open"))return void(this.style.display="none");this.style.display="block";const t=this.getType(),e=this.getVariant(),i=this.getSize(),s=this.getAttribute("title")||l[t],n=this.getAttribute("subtitle")||o[t],r=this.getAttribute("cta-text")||h[t],d=this.getBool("auto-close"),c=Math.max(Number(this.getAttribute("close-delay")||5e3),1e3),g=this.getBackground(),E=this.getAttribute("gradient-tone")||"vivid",u=this.getBool("show-countdown"),m=this.getAttribute("countdown-end-date");this.rootEl&&(this.rootEl.className=[a,`${a}--type-${t}`,`${a}--variant-${e}`,`${a}--size-${i}`,`${a}--bg-${g}`,d&&`${a}--auto-close`,"gradient"===g&&`${a}--with-gradient`,"gradient"===g&&"light"===E&&`${a}--gradient-light`].filter(Boolean).join(" ")),this.renderBackground(g,e),this.syncIcon(t),this.syncBadge(t),this.syncImage(t,this.getAttribute("image")),this.syncLink(t,this.getAttribute("href")),this.titleEl&&(this.titleEl.textContent=s),this.subtitleEl&&(this.subtitleEl.textContent=n),this.syncCountdown(u,m),this.actionsEl&&(this.actionsEl.hidden="topbar"===t),this.ctaEl&&(this.ctaEl.textContent=r,this.ctaEl.setAttribute("size",this.ctaButtonSize(t,i)),"floating"===t?this.ctaEl.setAttribute("full-width",""):this.ctaEl.removeAttribute("full-width")),this.progressEl&&(this.progressEl.hidden=!d),this.progressBarEl&&d&&(this.progressBarEl.style.width=`${this.progress}%`),this.stopAutoClose(),d&&this.startAutoClose(c)}}customElements.get("db-ad-banner")||customElements.define("db-ad-banner",DbAdBanner);export{DbAdBanner};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createDbIcon as
|
|
1
|
+
import{setHostClasses as t}from"../core/host-class.js";import{createDbIcon as e,isDbIconName as s}from"./db-icons.js";class DbAiChatList extends HTMLElement{constructor(){super(...arguments),this._items=[]}static get observedAttributes(){return["selected-id","new-label","title-label"]}get items(){return this._items}set items(t){this._items=Array.isArray(t)?t:[],this.render()}get selectedId(){return this.getAttribute("selected-id")||""}set selectedId(t){t?this.setAttribute("selected-id",t):this.removeAttribute("selected-id")}connectedCallback(){if(!this._items.length&&this.hasAttribute("items"))try{this._items=JSON.parse(this.getAttribute("items")||"[]")}catch{this._items=[]}this.render()}attributeChangedCallback(){this.render()}render(){t(this,["designbase-wc-ai-chat-list"]),this.replaceChildren();const i=document.createElement("button");i.type="button",i.className="designbase-wc-ai-chat-list__new";const n=document.createElement("span");n.className="designbase-wc-ai-chat-list__new-icon",n.append(e("plus",18));const a=document.createElement("span");if(a.textContent=this.getAttribute("new-label")||"새 대화",i.append(n,a),i.addEventListener("click",()=>{this.dispatchEvent(new CustomEvent("db-new",{bubbles:!0,composed:!0}))}),this.append(i),!this._items.length)return;const c=new Map,d=this.getAttribute("title-label")||"최근 항목";for(const t of this._items){const e=t.group||d;c.has(e)||c.set(e,[]),c.get(e).push(t)}const l=this.selectedId,o=document.createElement("div");o.className="designbase-wc-ai-chat-list__scroll";for(const[t,i]of c){const n=document.createElement("div");n.className="designbase-wc-ai-chat-list__group";const a=document.createElement("div");a.className="designbase-wc-ai-chat-list__group-title",a.textContent=t,n.append(a);for(const t of i){const i=document.createElement("button");if(i.type="button",i.className=["designbase-wc-ai-chat-list__item",t.id===l&&"designbase-wc-ai-chat-list__item--selected"].filter(Boolean).join(" "),t.icon&&s(t.icon)){const s=document.createElement("span");s.className="designbase-wc-ai-chat-list__item-icon",s.append(e(t.icon,16)),i.append(s)}const a=document.createElement("span");a.className="designbase-wc-ai-chat-list__item-title",a.textContent=t.title,i.append(a),i.addEventListener("click",()=>{this.selectedId=t.id,this.dispatchEvent(new CustomEvent("db-select",{detail:{id:t.id,title:t.title},bubbles:!0,composed:!0}))}),n.append(i)}o.append(n)}this.append(o)}}customElements.get("db-ai-chat-list")||customElements.define("db-ai-chat-list",DbAiChatList);export{DbAiChatList};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./db-chat-welcome.js";import"./db-chat-suggestions.js";import"./db-chat-message.js";import"./db-chat-typing.js";import"./db-chat-composer.js";import{createDbIcon as t,isDbIconName as e}from"./db-icons.js";import{sanitizeHtmlFragment as i}from"../core/safe-html.js";const s="designbase-wc-ai-chat";let a=0;function el(t,e,i){const s=document.createElement(t);return e&&(s.className=e),null!=i&&(s.textContent=i),s}class DbAiChat extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.typing=!1,this._messages=[],this._suggestions=[],this._tools=[],this._attachOptions=null,this.threadEl=null,this.activeArtifactId=null,this.artifactSeq=0,this.onSend=t=>{t.stopPropagation();const e=t.detail;this.dispatchEvent(new CustomEvent("db-send",{detail:e,bubbles:!0,composed:!0}))},this.onSuggestionSelect=t=>{t.stopPropagation();const e=t.detail,i=new CustomEvent("db-suggestion-select",{detail:e,bubbles:!0,composed:!0,cancelable:!0});this.dispatchEvent(i)&&(this.composer.value=e.value,this.composer.focusInput())}}static get observedAttributes(){return["greeting","title","highlight","subtitle","placeholder","orb-variant","suggestions-layout","suggestions-columns","disclaimer","voice","voice-state","voice-message","voice-disabled","attach","max-width","artifact-open","artifact-title"]}set messages(t){this._messages=Array.isArray(t)?t.map(t=>({id:`m${a+=1}`,...t})):[],this.built&&this.renderContent()}get messages(){return this._messages}set suggestions(t){this._suggestions=Array.isArray(t)?t:[],this.built&&0===this._messages.length&&this.renderContent()}get suggestions(){return this._suggestions}set tools(t){this._tools=Array.isArray(t)?t:[],this.built&&(this.composer.tools=this._tools)}get tools(){return this._tools}set attachOptions(t){this._attachOptions=Array.isArray(t)?t:null,this.built&&this._attachOptions&&(this.composer.attachOptions=this._attachOptions)}get attachOptions(){return this._attachOptions??this.composer?.attachOptions??[]}connectedCallback(){this.built||this.build(),this.sync()}attributeChangedCallback(t){this.built&&("placeholder"!==t?["voice","attach","voice-state","voice-message","voice-disabled"].includes(t)?this.syncComposerToggles():"disclaimer"!==t?"artifact-open"!==t?"artifact-title"!==t?this.sync():this.artifactTitleEl.textContent=this.getAttribute("artifact-title")||"":this.syncArtifact(!0):this.renderDock():this.composer.setAttribute("placeholder",this.getAttribute("placeholder")||""))}build(){this.built=!0,this.classList.add(s),this.replaceChildren(),this.mainEl=el("div",`${s}__main`),this.scrollEl=el("div",`${s}__scroll`),this.dockEl=el("div",`${s}__dock`),this.composer=document.createElement("db-chat-composer"),this.composer.className=`${s}__composer`,this.composer.addEventListener("db-send",this.onSend),this.composer.addEventListener("db-stop",t=>this.relay(t,"db-stop")),this.composer.addEventListener("db-tool-toggle",t=>this.relay(t,"db-tool-toggle")),this.composer.addEventListener("db-attach",t=>this.relay(t,"db-attach")),this.composer.addEventListener("db-attach-files",t=>this.relay(t,"db-attach-files")),this.composer.addEventListener("db-voice",t=>this.relay(t,"db-voice")),this.mainEl.append(this.scrollEl,this.dockEl),this.buildArtifact(),this.append(this.mainEl,this.artifactEl)}buildArtifact(){this.artifactEl=el("aside",`${s}__artifact`),this.artifactEl.setAttribute("aria-hidden","true");const e=el("div",`${s}__artifact-panel`),i=el("div",`${s}__artifact-header`),a=el("div",`${s}__artifact-titles`);this.artifactTitleEl=el("div",`${s}__artifact-title`),this.artifactSubtitleEl=el("div",`${s}__artifact-subtitle`),this.artifactSubtitleEl.hidden=!0,a.append(this.artifactTitleEl,this.artifactSubtitleEl);const r=el("button",`${s}__artifact-close`);r.type="button",r.setAttribute("aria-label","아티팩트 닫기"),r.append(t("close",18)),r.addEventListener("click",()=>this.closeArtifact()),i.append(a,r),this.artifactBodyEl=el("div",`${s}__artifact-body`),e.append(i,this.artifactBodyEl),this.artifactEl.append(e)}sync(){const t=this.getAttribute("max-width")||"100%";this.style.setProperty("--dbchat-max",t),this.syncComposerToggles(),this.composer.setAttribute("placeholder",this.getAttribute("placeholder")||"무엇이든 물어보세요…"),this._tools.length&&(this.composer.tools=this._tools),this._attachOptions&&(this.composer.attachOptions=this._attachOptions);const e=this.getAttribute("artifact-title");null!=e&&(this.artifactTitleEl.textContent=e),this.renderContent(),this.renderDock(),this.syncArtifact(!1)}syncArtifact(t){const e=this.hasAttribute("artifact-open");this.classList.toggle(`${s}--artifact-open`,e),this.artifactEl.setAttribute("aria-hidden",String(!e)),this.artifactEl.toggleAttribute("inert",!e),e||(this.activeArtifactId=null),this.syncArtifactCardStates(),t&&this.dispatchEvent(new CustomEvent(e?"db-artifact-open":"db-artifact-close",{detail:e?{id:this.activeArtifactId}:{id:null},bubbles:!0,composed:!0}))}syncComposerToggles(){this.composer.toggleAttribute("voice",this.hasAttribute("voice")),this.composer.setAttribute("voice-state",this.getAttribute("voice-state")||"idle"),this.composer.setAttribute("voice-message",this.getAttribute("voice-message")||""),this.composer.toggleAttribute("voice-disabled",this.hasAttribute("voice-disabled")),this.composer.toggleAttribute("attach","false"!==this.getAttribute("attach"))}renderContent(){this.scrollEl.replaceChildren(),this.threadEl=null;const t=0===this._messages.length;this.classList.toggle(`${s}--empty`,t),t?this.renderHero():this.renderThread()}renderHero(){const t=el("div",`${s}__hero`),e=document.createElement("db-chat-welcome");if(e.className=`${s}__welcome`,this.getAttribute("greeting")&&e.setAttribute("greeting",this.getAttribute("greeting")),e.setAttribute("title",this.getAttribute("title")||"무엇을 도와드릴까요?"),this.getAttribute("highlight")&&e.setAttribute("highlight",this.getAttribute("highlight")),this.getAttribute("subtitle")&&e.setAttribute("subtitle",this.getAttribute("subtitle")),e.setAttribute("orb-variant",this.getAttribute("orb-variant")||"aurora"),e.setAttribute("align","center"),t.append(e),this._suggestions.length){const e=document.createElement("db-chat-suggestions");e.className=`${s}__suggestions`,e.setAttribute("layout",this.getAttribute("suggestions-layout")||"card"),e.setAttribute("columns",this.getAttribute("suggestions-columns")||"3"),e.items=this._suggestions,e.addEventListener("db-select",this.onSuggestionSelect),t.append(e)}this.scrollEl.append(t)}renderThread(){const t=el("div",`${s}__thread`);this._messages.forEach(e=>t.append(this.buildMessage(e))),this.threadEl=t,this.scrollEl.append(t),this.typing&&t.append(this.buildTyping()),requestAnimationFrame(()=>this.scrollToEnd())}buildMessage(t){const e=el("div",`${s}__turn`);e.dataset.id=t.id||"";const a=el("db-chat-message");return a.dataset.id=t.id||"",a.setAttribute("role",t.role||"assistant"),t.name&&a.setAttribute("name",t.name),t.time&&a.setAttribute("timestamp",t.time),t.avatarSrc&&a.setAttribute("avatar-src",t.avatarSrc),t.avatarInitials&&a.setAttribute("avatar-initials",t.avatarInitials),t.actions&&a.setAttribute("actions",t.actions),t.status&&a.setAttribute("status",t.status),t.variant&&a.setAttribute("variant",t.variant),null!=t.html?a.replaceChildren(i(t.html)):a.textContent=t.text||"",a.addEventListener("db-action",t=>this.relay(t,"db-message-action")),e.append(a),t.artifact&&(this.ensureArtifactId(t.artifact),e.append(this.buildArtifactCard(t.artifact))),e}ensureArtifactId(t){return t.id||(t.id=`art-${this.artifactSeq+=1}`),t.id}buildArtifactCard(i){const a=this.ensureArtifactId(i),r=el("button",`${s}__artifact-card`);r.type="button",r.dataset.artifactId=a,r.setAttribute("aria-pressed","false"),r.setAttribute("aria-label",`${i.title} 아티팩트 열기`);const c=el("span",`${s}__artifact-card-icon`),n=i.icon&&e(i.icon)?i.icon:"code";c.append(t(n,18));const l=el("div",`${s}__artifact-card-meta`);l.append(el("div",`${s}__artifact-card-title`,i.title)),i.subtitle&&l.append(el("div",`${s}__artifact-card-subtitle`,i.subtitle));const o=el("span",`${s}__artifact-card-chevron`);return o.append(t("chevron-right",16)),r.append(c,l,o),r.addEventListener("click",()=>this.toggleArtifactFromCard(i)),r}syncArtifactCardStates(){this.querySelectorAll(`.${s}__artifact-card`).forEach(t=>{const e=t,i=this.artifactOpen&&e.dataset.artifactId===this.activeArtifactId;e.classList.toggle(`${s}__artifact-card--active`,i),e.setAttribute("aria-pressed",String(i))})}toggleArtifactFromCard(t){const e=this.ensureArtifactId(t);this.artifactOpen&&this.activeArtifactId===e?this.closeArtifact():this.openArtifact({id:e,title:t.title,subtitle:t.subtitle,html:t.html})}buildTyping(){const t=el("db-chat-typing",`${s}__typing`),e=this.getAttribute("title")||"AI";return t.setAttribute("name",this.getAttribute("agent-name")||e),t.setAttribute("label","생각 중…"),t.setAttribute("avatar-initials","AI"),t}renderDock(){this.dockEl.replaceChildren(),this.dockEl.append(this.composer);const t=this.getAttribute("disclaimer");t&&this.dockEl.append(el("p",`${s}__disclaimer`,t))}relay(t,e){t.stopPropagation(),this.dispatchEvent(new CustomEvent(e,{detail:t.detail,bubbles:!0,composed:!0}))}scrollToEnd(){this.scrollEl.scrollTop=this.scrollEl.scrollHeight}addMessage(t){const e={id:`m${a+=1}`,...t},i=0===this._messages.length;if(this._messages.push(e),i||!this.threadEl)this.renderContent();else{const t=this.threadEl.querySelector("db-chat-typing"),i=this.buildMessage(e);t?this.threadEl.insertBefore(i,t):this.threadEl.append(i),requestAnimationFrame(()=>this.scrollToEnd())}return e.id}updateMessage(t,e){const a=this._messages.find(e=>e.id===t);if(!a)return;Object.assign(a,e);const r=this.threadEl?.querySelector(`db-chat-message[data-id="${t}"]`);if(!r)return;const c=r.querySelector(".designbase-wc-chat-message__content");if(!c||null==e.html&&null==e.text||(null!=e.html?c.replaceChildren(i(e.html)):c.textContent=e.text||""),e.status&&r.setAttribute("status",e.status),void 0!==e.artifact){const t=r.closest(`.${s}__turn`)||r.parentElement;t?.querySelector(`.${s}__artifact-card`)?.remove(),e.artifact&&t&&(this.ensureArtifactId(e.artifact),t.append(this.buildArtifactCard(e.artifact)),this.syncArtifactCardStates())}requestAnimationFrame(()=>this.scrollToEnd())}appendToMessage(t,e){const i=this._messages.find(e=>e.id===t);if(!i)return;i.text=(i.text||"")+e;const s=this.threadEl?.querySelector(`db-chat-message[data-id="${t}"]`),a=s?.querySelector(".designbase-wc-chat-message__content");a&&(a.textContent=i.text),requestAnimationFrame(()=>this.scrollToEnd())}setMessages(t){this.messages=t}clear(){this._messages=[],this.typing=!1,this.closeArtifact(),this.built&&this.renderContent()}setTyping(t){if(this.typing=Boolean(t),!this.built||!this.threadEl)return;const e=this.threadEl.querySelector("db-chat-typing");this.typing&&!e?(this.threadEl.append(this.buildTyping()),requestAnimationFrame(()=>this.scrollToEnd())):!this.typing&&e&&e.remove()}setStreaming(t){this.composer?.setStreaming(Boolean(t))}focusInput(){this.composer?.focusInput()}getComposer(){return this.composer}get artifactOpen(){return this.hasAttribute("artifact-open")}set artifactOpen(t){this.toggleAttribute("artifact-open",t)}openArtifact(t={}){null!=t.title&&(this.artifactTitleEl.textContent=t.title),null!=t.subtitle&&(this.artifactSubtitleEl.textContent=t.subtitle,this.artifactSubtitleEl.hidden=!t.subtitle),null!=t.html&&this.artifactBodyEl.replaceChildren(i(t.html)),null!=t.id&&(this.activeArtifactId=t.id);const e=this.artifactOpen;this.artifactOpen=!0,e&&this.syncArtifactCardStates()}closeArtifact(){this.activeArtifactId=null;const t=this.artifactOpen;this.artifactOpen=!1,t||this.syncArtifactCardStates()}toggleArtifact(){this.artifactOpen?this.closeArtifact():this.artifactOpen=!0}getArtifactBody(){return this.artifactBodyEl}setArtifactContent(t){this.artifactBodyEl.replaceChildren(t)}}customElements.get("db-ai-chat")||customElements.define("db-ai-chat",DbAiChat);export{DbAiChat};
|
|
1
|
+
import{dbText as t,dbFormat as e}from"../core/i18n.js";import"./db-chat-welcome.js";import"./db-chat-suggestions.js";import"./db-chat-message.js";import"./db-chat-typing.js";import"./db-chat-composer.js";import{createDbIcon as i,isDbIconName as s}from"./db-icons.js";import{sanitizeHtmlFragment as a}from"../core/safe-html.js";const r="designbase-wc-ai-chat";let c=0;function el(t,e,i){const s=document.createElement(t);return e&&(s.className=e),null!=i&&(s.textContent=i),s}class DbAiChat extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.typing=!1,this._messages=[],this._suggestions=[],this._tools=[],this._attachOptions=null,this.threadEl=null,this.activeArtifactId=null,this.artifactSeq=0,this.onSend=t=>{t.stopPropagation();const e=t.detail;this.dispatchEvent(new CustomEvent("db-send",{detail:e,bubbles:!0,composed:!0}))},this.onSuggestionSelect=t=>{t.stopPropagation();const e=t.detail,i=new CustomEvent("db-suggestion-select",{detail:e,bubbles:!0,composed:!0,cancelable:!0});this.dispatchEvent(i)&&(this.composer.value=e.value,this.composer.focusInput())}}static get observedAttributes(){return["greeting","title","highlight","subtitle","placeholder","orb-variant","suggestions-layout","suggestions-columns","disclaimer","voice","voice-state","voice-message","voice-disabled","attach","max-width","artifact-open","artifact-title"]}set messages(t){this._messages=Array.isArray(t)?t.map(t=>({id:`m${c+=1}`,...t})):[],this.built&&this.renderContent()}get messages(){return this._messages}set suggestions(t){this._suggestions=Array.isArray(t)?t:[],this.built&&0===this._messages.length&&this.renderContent()}get suggestions(){return this._suggestions}set tools(t){this._tools=Array.isArray(t)?t:[],this.built&&(this.composer.tools=this._tools)}get tools(){return this._tools}set attachOptions(t){this._attachOptions=Array.isArray(t)?t:null,this.built&&this._attachOptions&&(this.composer.attachOptions=this._attachOptions)}get attachOptions(){return this._attachOptions??this.composer?.attachOptions??[]}connectedCallback(){this.built||this.build(),this.sync()}attributeChangedCallback(t){this.built&&("placeholder"!==t?["voice","attach","voice-state","voice-message","voice-disabled"].includes(t)?this.syncComposerToggles():"disclaimer"!==t?"artifact-open"!==t?"artifact-title"!==t?this.sync():this.artifactTitleEl.textContent=this.getAttribute("artifact-title")||"":this.syncArtifact(!0):this.renderDock():this.composer.setAttribute("placeholder",this.getAttribute("placeholder")||""))}build(){this.built=!0,this.classList.add(r),this.replaceChildren(),this.mainEl=el("div",`${r}__main`),this.scrollEl=el("div",`${r}__scroll`),this.dockEl=el("div",`${r}__dock`),this.composer=document.createElement("db-chat-composer"),this.composer.className=`${r}__composer`,this.composer.addEventListener("db-send",this.onSend),this.composer.addEventListener("db-stop",t=>this.relay(t,"db-stop")),this.composer.addEventListener("db-tool-toggle",t=>this.relay(t,"db-tool-toggle")),this.composer.addEventListener("db-attach",t=>this.relay(t,"db-attach")),this.composer.addEventListener("db-attach-files",t=>this.relay(t,"db-attach-files")),this.composer.addEventListener("db-voice",t=>this.relay(t,"db-voice")),this.mainEl.append(this.scrollEl,this.dockEl),this.buildArtifact(),this.append(this.mainEl,this.artifactEl)}buildArtifact(){this.artifactEl=el("aside",`${r}__artifact`),this.artifactEl.setAttribute("aria-hidden","true");const e=el("div",`${r}__artifact-panel`),s=el("div",`${r}__artifact-header`),a=el("div",`${r}__artifact-titles`);this.artifactTitleEl=el("div",`${r}__artifact-title`),this.artifactSubtitleEl=el("div",`${r}__artifact-subtitle`),this.artifactSubtitleEl.hidden=!0,a.append(this.artifactTitleEl,this.artifactSubtitleEl);const c=el("button",`${r}__artifact-close`);c.type="button",c.setAttribute("aria-label",t("아티팩트 닫기")),c.append(i("close",18)),c.addEventListener("click",()=>this.closeArtifact()),s.append(a,c),this.artifactBodyEl=el("div",`${r}__artifact-body`),e.append(s,this.artifactBodyEl),this.artifactEl.append(e)}sync(){const t=this.getAttribute("max-width")||"100%";this.style.setProperty("--dbchat-max",t),this.syncComposerToggles(),this.composer.setAttribute("placeholder",this.getAttribute("placeholder")||"무엇이든 물어보세요…"),this._tools.length&&(this.composer.tools=this._tools),this._attachOptions&&(this.composer.attachOptions=this._attachOptions);const e=this.getAttribute("artifact-title");null!=e&&(this.artifactTitleEl.textContent=e),this.renderContent(),this.renderDock(),this.syncArtifact(!1)}syncArtifact(t){const e=this.hasAttribute("artifact-open");this.classList.toggle(`${r}--artifact-open`,e),this.artifactEl.setAttribute("aria-hidden",String(!e)),this.artifactEl.toggleAttribute("inert",!e),e||(this.activeArtifactId=null),this.syncArtifactCardStates(),t&&this.dispatchEvent(new CustomEvent(e?"db-artifact-open":"db-artifact-close",{detail:e?{id:this.activeArtifactId}:{id:null},bubbles:!0,composed:!0}))}syncComposerToggles(){this.composer.toggleAttribute("voice",this.hasAttribute("voice")),this.composer.setAttribute("voice-state",this.getAttribute("voice-state")||"idle"),this.composer.setAttribute("voice-message",this.getAttribute("voice-message")||""),this.composer.toggleAttribute("voice-disabled",this.hasAttribute("voice-disabled")),this.composer.toggleAttribute("attach","false"!==this.getAttribute("attach"))}renderContent(){this.scrollEl.replaceChildren(),this.threadEl=null;const t=0===this._messages.length;this.classList.toggle(`${r}--empty`,t),t?this.renderHero():this.renderThread()}renderHero(){const t=el("div",`${r}__hero`),e=document.createElement("db-chat-welcome");if(e.className=`${r}__welcome`,this.getAttribute("greeting")&&e.setAttribute("greeting",this.getAttribute("greeting")),e.setAttribute("title",this.getAttribute("title")||"무엇을 도와드릴까요?"),this.getAttribute("highlight")&&e.setAttribute("highlight",this.getAttribute("highlight")),this.getAttribute("subtitle")&&e.setAttribute("subtitle",this.getAttribute("subtitle")),e.setAttribute("orb-variant",this.getAttribute("orb-variant")||"aurora"),e.setAttribute("align","center"),t.append(e),this._suggestions.length){const e=document.createElement("db-chat-suggestions");e.className=`${r}__suggestions`,e.setAttribute("layout",this.getAttribute("suggestions-layout")||"card"),e.setAttribute("columns",this.getAttribute("suggestions-columns")||"3"),e.items=this._suggestions,e.addEventListener("db-select",this.onSuggestionSelect),t.append(e)}this.scrollEl.append(t)}renderThread(){const t=el("div",`${r}__thread`);this._messages.forEach(e=>t.append(this.buildMessage(e))),this.threadEl=t,this.scrollEl.append(t),this.typing&&t.append(this.buildTyping()),requestAnimationFrame(()=>this.scrollToEnd())}buildMessage(t){const e=el("div",`${r}__turn`);e.dataset.id=t.id||"";const i=el("db-chat-message");return i.dataset.id=t.id||"",i.setAttribute("role",t.role||"assistant"),t.name&&i.setAttribute("name",t.name),t.time&&i.setAttribute("timestamp",t.time),t.avatarSrc&&i.setAttribute("avatar-src",t.avatarSrc),t.avatarInitials&&i.setAttribute("avatar-initials",t.avatarInitials),t.actions&&i.setAttribute("actions",t.actions),t.status&&i.setAttribute("status",t.status),t.variant&&i.setAttribute("variant",t.variant),null!=t.html?i.replaceChildren(a(t.html)):i.textContent=t.text||"",i.addEventListener("db-action",t=>this.relay(t,"db-message-action")),e.append(i),t.artifact&&(this.ensureArtifactId(t.artifact),e.append(this.buildArtifactCard(t.artifact))),e}ensureArtifactId(t){return t.id||(t.id=`art-${this.artifactSeq+=1}`),t.id}buildArtifactCard(t){const a=this.ensureArtifactId(t),c=el("button",`${r}__artifact-card`);c.type="button",c.dataset.artifactId=a,c.setAttribute("aria-pressed","false"),c.setAttribute("aria-label",e("{0} 아티팩트 열기",[t.title]));const n=el("span",`${r}__artifact-card-icon`),l=t.icon&&s(t.icon)?t.icon:"code";n.append(i(l,18));const o=el("div",`${r}__artifact-card-meta`);o.append(el("div",`${r}__artifact-card-title`,t.title)),t.subtitle&&o.append(el("div",`${r}__artifact-card-subtitle`,t.subtitle));const h=el("span",`${r}__artifact-card-chevron`);return h.append(i("chevron-right",16)),c.append(n,o,h),c.addEventListener("click",()=>this.toggleArtifactFromCard(t)),c}syncArtifactCardStates(){this.querySelectorAll(`.${r}__artifact-card`).forEach(t=>{const e=t,i=this.artifactOpen&&e.dataset.artifactId===this.activeArtifactId;e.classList.toggle(`${r}__artifact-card--active`,i),e.setAttribute("aria-pressed",String(i))})}toggleArtifactFromCard(t){const e=this.ensureArtifactId(t);this.artifactOpen&&this.activeArtifactId===e?this.closeArtifact():this.openArtifact({id:e,title:t.title,subtitle:t.subtitle,html:t.html})}buildTyping(){const t=el("db-chat-typing",`${r}__typing`),e=this.getAttribute("title")||"AI";return t.setAttribute("name",this.getAttribute("agent-name")||e),t.setAttribute("label","생각 중…"),t.setAttribute("avatar-initials","AI"),t}renderDock(){this.dockEl.replaceChildren(),this.dockEl.append(this.composer);const t=this.getAttribute("disclaimer");t&&this.dockEl.append(el("p",`${r}__disclaimer`,t))}relay(t,e){t.stopPropagation(),this.dispatchEvent(new CustomEvent(e,{detail:t.detail,bubbles:!0,composed:!0}))}scrollToEnd(){this.scrollEl.scrollTop=this.scrollEl.scrollHeight}addMessage(t){const e={id:`m${c+=1}`,...t},i=0===this._messages.length;if(this._messages.push(e),i||!this.threadEl)this.renderContent();else{const t=this.threadEl.querySelector("db-chat-typing"),i=this.buildMessage(e);t?this.threadEl.insertBefore(i,t):this.threadEl.append(i),requestAnimationFrame(()=>this.scrollToEnd())}return e.id}updateMessage(t,e){const i=this._messages.find(e=>e.id===t);if(!i)return;Object.assign(i,e);const s=this.threadEl?.querySelector(`db-chat-message[data-id="${t}"]`);if(!s)return;const c=s.querySelector(".designbase-wc-chat-message__content");if(!c||null==e.html&&null==e.text||(null!=e.html?c.replaceChildren(a(e.html)):c.textContent=e.text||""),e.status&&s.setAttribute("status",e.status),void 0!==e.artifact){const t=s.closest(`.${r}__turn`)||s.parentElement;t?.querySelector(`.${r}__artifact-card`)?.remove(),e.artifact&&t&&(this.ensureArtifactId(e.artifact),t.append(this.buildArtifactCard(e.artifact)),this.syncArtifactCardStates())}requestAnimationFrame(()=>this.scrollToEnd())}appendToMessage(t,e){const i=this._messages.find(e=>e.id===t);if(!i)return;i.text=(i.text||"")+e;const s=this.threadEl?.querySelector(`db-chat-message[data-id="${t}"]`),a=s?.querySelector(".designbase-wc-chat-message__content");a&&(a.textContent=i.text),requestAnimationFrame(()=>this.scrollToEnd())}setMessages(t){this.messages=t}clear(){this._messages=[],this.typing=!1,this.closeArtifact(),this.built&&this.renderContent()}setTyping(t){if(this.typing=Boolean(t),!this.built||!this.threadEl)return;const e=this.threadEl.querySelector("db-chat-typing");this.typing&&!e?(this.threadEl.append(this.buildTyping()),requestAnimationFrame(()=>this.scrollToEnd())):!this.typing&&e&&e.remove()}setStreaming(t){this.composer?.setStreaming(Boolean(t))}focusInput(){this.composer?.focusInput()}getComposer(){return this.composer}get artifactOpen(){return this.hasAttribute("artifact-open")}set artifactOpen(t){this.toggleAttribute("artifact-open",t)}openArtifact(t={}){null!=t.title&&(this.artifactTitleEl.textContent=t.title),null!=t.subtitle&&(this.artifactSubtitleEl.textContent=t.subtitle,this.artifactSubtitleEl.hidden=!t.subtitle),null!=t.html&&this.artifactBodyEl.replaceChildren(a(t.html)),null!=t.id&&(this.activeArtifactId=t.id);const e=this.artifactOpen;this.artifactOpen=!0,e&&this.syncArtifactCardStates()}closeArtifact(){this.activeArtifactId=null;const t=this.artifactOpen;this.artifactOpen=!1,t||this.syncArtifactCardStates()}toggleArtifact(){this.artifactOpen?this.closeArtifact():this.artifactOpen=!0}getArtifactBody(){return this.artifactBodyEl}setArtifactContent(t){this.artifactBodyEl.replaceChildren(t)}}customElements.get("db-ai-chat")||customElements.define("db-ai-chat",DbAiChat);export{DbAiChat};
|
|
@@ -8,8 +8,20 @@ interface DbAlertAction {
|
|
|
8
8
|
}
|
|
9
9
|
declare class DbAlert extends HTMLElement {
|
|
10
10
|
static get observedAttributes(): string[];
|
|
11
|
+
/** 소비자가 넣은 자식(링크·코드 등)을 담아 두는 내부 컨테이너. 렌더 사이에 유지된다. */
|
|
12
|
+
private slotEl?;
|
|
13
|
+
private observer?;
|
|
14
|
+
/** 슬롯 내부 변경(React 가 래퍼 안 자식을 바꿀 때)을 감지해 빈 슬롯 여부를 다시 계산한다 */
|
|
15
|
+
private slotObserver?;
|
|
16
|
+
private renderedSlotted;
|
|
11
17
|
connectedCallback(): void;
|
|
18
|
+
disconnectedCallback(): void;
|
|
12
19
|
attributeChangedCallback(): void;
|
|
20
|
+
private getSlot;
|
|
21
|
+
/** 호스트에 직접 붙은 소비자 노드를 슬롯으로 옮긴다. 공백 텍스트는 버린다. */
|
|
22
|
+
private moveChildrenToSlot;
|
|
23
|
+
private adoptChildren;
|
|
24
|
+
private hasSlotted;
|
|
13
25
|
private getIconName;
|
|
14
26
|
private parseActionButtons;
|
|
15
27
|
private render;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./db-button.js";import{createDbIcon as
|
|
1
|
+
import{dbText as t}from"../core/i18n.js";import{setHostClasses as e}from"../core/host-class.js";import"./db-button.js";import{createDbIcon as s}from"./db-icons.js";import{coerceToContract as i}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{ALERT_VARIANTS as n,ALERT_SIZES as o}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const r="designbase-wc-alert";class DbAlert extends HTMLElement{constructor(){super(...arguments),this.renderedSlotted=!1}static get observedAttributes(){return["title","message","variant","size","show-icon","closable","action-label","action-variant","action-buttons"]}connectedCallback(){this.render(),this.observer??(this.observer=new MutationObserver(()=>this.adoptChildren())),this.observer.observe(this,{childList:!0}),this.slotObserver??(this.slotObserver=new MutationObserver(()=>{this.hasSlotted()!==this.renderedSlotted&&this.render()})),this.slotObserver.observe(this.getSlot(),{childList:!0,subtree:!0,characterData:!0})}disconnectedCallback(){this.observer?.disconnect(),this.slotObserver?.disconnect()}attributeChangedCallback(){this.isConnected&&this.render()}getSlot(){return this.slotEl||(this.slotEl=document.createElement("div"),this.slotEl.className=`${r}__slot`,this.slotEl.setAttribute("data-wc-internal","")),this.slotEl}moveChildrenToSlot(){const t=this.getSlot();let e=!1;for(const s of Array.from(this.childNodes))s instanceof Element&&s.hasAttribute("data-wc-internal")||s.nodeType!==Node.COMMENT_NODE&&(s.nodeType!==Node.TEXT_NODE||s.textContent?.trim()?(t.append(s),e=!0):s.remove());return e}adoptChildren(){this.moveChildrenToSlot()&&this.render()}hasSlotted(){const hasContent=t=>t.nodeType===Node.TEXT_NODE?Boolean(t.textContent?.trim()):t instanceof Element&&(!t.hasAttribute("data-db-children")||Array.from(t.childNodes).some(hasContent));return Boolean(this.slotEl&&Array.from(this.slotEl.childNodes).some(hasContent))}getIconName(t){return"success"===t?"circle-checked":"warning"===t?"warning-filled":"danger"===t?"error-filled":"info-filled"}parseActionButtons(){const t=this.getAttribute("action-buttons");if(!t)return[];try{const e=JSON.parse(t);return Array.isArray(e)?e:[]}catch{return[]}}render(){const a=i(this.getAttribute("variant"),n,"default"),l=i(this.getAttribute("size"),o,"m"),c="false"!==this.getAttribute("show-icon"),d=this.hasAttribute("closable")&&"false"!==this.getAttribute("closable"),h=this.getAttribute("title")?.trim()||"",b=this.getAttribute("message")?.trim()||"",m=this.getAttribute("action-label"),u=this.getAttribute("action-variant")||"tertiary",p=this.parseActionButtons(),v=Boolean(b),E=Boolean(h);this.moveChildrenToSlot();const A=this.hasSlotted();this.renderedSlotted=A;const g=1===Number(E)+Number(v)+Number(A),f=p.length>0?p:m?[{label:m,variant:u}]:[];e(this,[r,`${r}--${a}`,`${r}--${l}`,c&&`${r}--with-icon`,d&&`${r}--closable`,g&&`${r}--text-single`,f.length>0&&`${r}--has-actions`]),this.setAttribute("role","alert"),this.setAttribute("aria-live","polite");const N=this.getSlot(),_=document.createElement("div");if(_.className=`${r}__content`,_.setAttribute("data-wc-internal",""),c){const t=document.createElement("div");t.className=`${r}__icon`,t.append(s(this.getIconName(a),"s"===l?16:"l"===l?24:20)),_.append(t)}const C=document.createElement("div");if(C.className=`${r}__body`,E){const t=document.createElement("div");t.className=`${r}__title`,t.textContent=h,C.append(t)}if(v){const t=document.createElement("div");t.className=`${r}__message`,t.textContent=b,C.append(t)}if(A?C.append(N):N.remove(),_.append(C),f.length>0){const t=document.createElement("div");t.className=`${r}__actions`,t.setAttribute("data-wc-internal","");const e=document.createElement("div");e.className=`${r}__action-buttons`,f.forEach((t,s)=>{const i=document.createElement("db-button");i.setAttribute("variant",t.variant||"tertiary"),i.setAttribute("size",t.size||l),i.textContent=t.label,t.disabled&&i.setAttribute("disabled",""),i.addEventListener("db-click",()=>{this.dispatchEvent(new CustomEvent("db-action",{bubbles:!0,composed:!0,detail:{index:s,label:t.label}}))}),e.append(i)}),t.append(e),_.append(t)}if(d){const e=document.createElement("button");e.type="button",e.className=`${r}__close`,e.setAttribute("aria-label",t("알림 닫기")),e.append(s("close",20)),e.addEventListener("click",()=>{this.hidden=!0,this.dispatchEvent(new CustomEvent("db-close",{bubbles:!0,composed:!0}))}),_.append(e)}this.observer?.disconnect(),this.replaceChildren(_),this.isConnected&&this.observer?.observe(this,{childList:!0})}}customElements.get("db-alert")||customElements.define("db-alert",DbAlert);export{DbAlert};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{dbText as t}from"../core/i18n.js";import{createDbIcon as e}from"./db-icons.js";import{activateOnKey as s}from"../core/a11y.js";import{sanitizeHref as i}from"../core/safe-url.js";import{coerceToContract as o}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{APP_BADGE_SIZES as a}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const r="designbase-wc-app-badge";class DbAppBadge extends HTMLElement{constructor(){super(...arguments),this.built=!1}static get observedAttributes(){return["store","href","label","store-name","size","theme"]}connectedCallback(){this.built||(this.built=!0,this.build()),this.updateUI()}attributeChangedCallback(){this.built&&this.updateUI()}getStore(){return"google-play"===(this.getAttribute("store")||"app-store")?"google-play":"app-store"}getIconSize(){const t=o(this.getAttribute("size"),a,"m");return"s"===t?18:"l"===t?24:20}build(){this.iconWrapEl=document.createElement("span"),this.iconWrapEl.className=`${r}__icon`,this.iconWrapEl.setAttribute("aria-hidden","true");const t=document.createElement("span");t.className=`${r}__text`,this.labelEl=document.createElement("span"),this.labelEl.className=`${r}__label`,this.storeEl=document.createElement("span"),this.storeEl.className=`${r}__store`,t.append(this.labelEl,this.storeEl),this.append(this.iconWrapEl,t),this.addEventListener("click",t=>{this.getAttribute("href")||this.dispatchEvent(new CustomEvent("db-click",{bubbles:!0,composed:!0,detail:{event:t}}))}),this.detachKeyActivation=s(this)}disconnectedCallback(){this.detachKeyActivation?.(),this.detachKeyActivation=void 0}updateUI(){const s=this.getStore(),l={"app-store":{label:t("다운로드"),storeName:"App Store"},"google-play":{label:t("다운로드"),storeName:"Google Play"}}[s],n=o(this.getAttribute("size"),a,"m"),c=this.getAttribute("theme")||"dark",p=this.getAttribute("label")||l.label,h=this.getAttribute("store-name")||l.storeName,b=i(this.getAttribute("href"),"");this.className=[r,`${r}--${n}`,`${r}--${c}`,`${r}--${s}`].join(" "),b?(this.setAttribute("role","link"),this.tabIndex=0,this.onclick=()=>window.open(b,"_blank","noopener,noreferrer")):(this.onclick=null,this.setAttribute("role","button"),this.tabIndex=0),this.iconWrapEl&&this.iconWrapEl.replaceChildren(e("app-store"===s?"apple":"play-store",this.getIconSize())),this.labelEl&&(this.labelEl.textContent=p),this.storeEl&&(this.storeEl.textContent=h)}}customElements.get("db-app-badge")||customElements.define("db-app-badge",DbAppBadge);export{DbAppBadge};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createDbIcon as t}from"./db-icons.js";import{t as e}from"../core/i18n.js";import{coerceToContract as s}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{AUDIO_PLAYER_SIZES as i,AUDIO_PLAYER_VARIANTS as l}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const a="designbase-wc-audio-player";class DbAudioPlayer extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.isPlaying=!1,this.isMuted=!1,this.volume=1,this.currentTime=0,this.duration=0,this.showSettingsMenu=!1,this.playbackRate=1,this.currentRepeatMode="none",this.isShuffle=!1,this.isLoading=!1,this.error=null,this.playlistIndex=0,this.shuffledPlaylist=[],this.boundKeyDown=t=>this.handleKeyDown(t)}static get observedAttributes(){return["src","title","artist","album","album-art","size","variant","theme","auto-play","loop","muted","show-controls","enable-keyboard","show-progress","show-time","show-volume","show-settings","playlist","current-index","playback-rates","default-playback-rate","repeat-mode","shuffle"]}connectedCallback(){this.style.display="block",this.built||(this.built=!0,this.build(),this.bindAudioEvents()),this.syncFromAttributes(),this.updateUI(),this.getBool("enable-keyboard",!0)&&document.addEventListener("keydown",this.boundKeyDown)}disconnectedCallback(){document.removeEventListener("keydown",this.boundKeyDown)}attributeChangedCallback(t){if(this.built){if("current-index"===t)return this.playlistIndex=Number(this.getAttribute("current-index")||0),void this.loadCurrentTrack();"repeat-mode"===t&&(this.currentRepeatMode=this.getAttribute("repeat-mode")||"none"),"shuffle"===t&&(this.isShuffle=this.getBool("shuffle"),this.refreshShuffledPlaylist()),"default-playback-rate"===t&&(this.playbackRate=Number(this.getAttribute("default-playback-rate")||1),this.audioEl&&(this.audioEl.playbackRate=this.playbackRate)),this.updateUI()}}getBool(t,e=!1){if(!this.hasAttribute(t))return e;const s=this.getAttribute(t);return""===s||"true"===s}getPlaylist(){try{const t=this.getAttribute("playlist"),e=t?JSON.parse(t):[];return Array.isArray(e)?e:[]}catch{return[]}}getPlaybackRates(){try{const t=this.getAttribute("playback-rates"),e=t?JSON.parse(t):[.5,.75,1,1.25,1.5,2];return Array.isArray(e)&&e.length>0?e:[.5,.75,1,1.25,1.5,2]}catch{return[.5,.75,1,1.25,1.5,2]}}getIconSize(){const t=s(this.getAttribute("size"),i,"m");return"s"===t?16:"l"===t?24:"xl"===t?32:20}getCurrentTrack(){const t=this.getPlaylist();if(t.length>0){return t[this.isShuffle&&this.shuffledPlaylist.length>0?this.shuffledPlaylist[this.playlistIndex]??this.playlistIndex:this.playlistIndex]||t[0]}return{src:this.getAttribute("src")||"",title:this.getAttribute("title")||void 0,artist:this.getAttribute("artist")||void 0,album:this.getAttribute("album")||void 0,albumArt:this.getAttribute("album-art")||void 0}}refreshShuffledPlaylist(){const t=this.getPlaylist();if(t.length>0&&this.isShuffle){const e=Array.from({length:t.length},(t,e)=>e);this.shuffledPlaylist=[...e].sort(()=>Math.random()-.5)}else this.shuffledPlaylist=[]}formatTime(t){return`${Math.floor(t/60)}:${Math.floor(t%60).toString().padStart(2,"0")}`}syncFromAttributes(){this.playlistIndex=Number(this.getAttribute("current-index")||0),this.currentRepeatMode=this.getAttribute("repeat-mode")||"none",this.isShuffle=this.getBool("shuffle"),this.playbackRate=Number(this.getAttribute("default-playback-rate")||1),this.isMuted=this.getBool("muted"),this.volume=this.isMuted?0:1,this.refreshShuffledPlaylist(),this.loadCurrentTrack()}loadCurrentTrack(){if(!this.audioEl)return;const t=this.getCurrentTrack(),e=t?.src||this.getAttribute("src")||"";this.audioEl.src!==e&&e&&(this.audioEl.src=e,this.audioEl.load()),this.updateTrackInfo(),this.updatePlaylistActive()}bindAudioEvents(){const t=this.audioEl;t&&(t.addEventListener("play",()=>{this.isPlaying=!0,this.dispatchEvent(new CustomEvent("db-play",{bubbles:!0,composed:!0})),this.updateUI()}),t.addEventListener("pause",()=>{this.isPlaying=!1,this.dispatchEvent(new CustomEvent("db-pause",{bubbles:!0,composed:!0})),this.updateUI()}),t.addEventListener("timeupdate",()=>{this.currentTime=t.currentTime,this.duration=t.duration||0,this.dispatchEvent(new CustomEvent("db-time-update",{detail:{currentTime:this.currentTime,duration:this.duration},bubbles:!0,composed:!0})),this.updateProgress(),this.updateTime()}),t.addEventListener("volumechange",()=>{this.volume=t.volume,this.isMuted=t.muted,this.dispatchEvent(new CustomEvent("db-volume-change",{detail:{volume:this.volume},bubbles:!0,composed:!0})),this.updateVolumeUI()}),t.addEventListener("ended",()=>this.handleEnded()),t.addEventListener("error",()=>{this.error="오디오를 재생할 수 없습니다.",this.dispatchEvent(new CustomEvent("db-error",{detail:{error:this.error},bubbles:!0,composed:!0})),this.updateUI()}),t.addEventListener("loadstart",()=>{this.isLoading=!0,this.error=null,this.updateUI()}),t.addEventListener("canplay",()=>{this.isLoading=!1,this.updateUI()}))}handleEnded(){this.isPlaying=!1,this.dispatchEvent(new CustomEvent("db-ended",{bubbles:!0,composed:!0}));const t=this.getPlaylist();if(t.length>0){if("one"===this.currentRepeatMode)this.audioEl&&(this.audioEl.currentTime=0,this.audioEl.play());else if("all"===this.currentRepeatMode||this.playlistIndex<t.length-1){const e=this.playlistIndex+1;e<t.length?this.setPlaylistIndex(e):"all"===this.currentRepeatMode&&this.setPlaylistIndex(0)}}else this.getBool("loop")&&this.audioEl&&(this.audioEl.currentTime=0,this.audioEl.play());this.updateUI()}setPlaylistIndex(t){this.playlistIndex=t,this.dispatchEvent(new CustomEvent("db-playlist-change",{detail:{index:t},bubbles:!0,composed:!0})),this.loadCurrentTrack(),this.audioEl&&this.audioEl.play()}togglePlay(){this.audioEl&&(this.isPlaying?this.audioEl.pause():this.audioEl.play())}toggleMute(){this.audioEl&&(this.audioEl.muted=!this.isMuted)}toggleRepeatMode(){const t=["none","one","all"],e=t[(t.indexOf(this.currentRepeatMode)+1)%t.length];this.currentRepeatMode=e,this.dispatchEvent(new CustomEvent("db-repeat-mode-change",{detail:{mode:e},bubbles:!0,composed:!0})),this.updateUI()}toggleShuffle(){this.isShuffle=!this.isShuffle,this.refreshShuffledPlaylist(),this.dispatchEvent(new CustomEvent("db-shuffle-change",{detail:{shuffle:this.isShuffle},bubbles:!0,composed:!0})),this.updateUI()}handlePlaybackRateChange(t){this.audioEl&&(this.audioEl.playbackRate=t,this.playbackRate=t,this.dispatchEvent(new CustomEvent("db-playback-rate-change",{detail:{rate:t},bubbles:!0,composed:!0})))}handleKeyDown(t){if(this.audioEl&&this.getBool("enable-keyboard",!0))switch(t.code){case"Space":t.preventDefault(),this.togglePlay();break;case"ArrowLeft":t.preventDefault(),this.audioEl.currentTime=Math.max(0,this.currentTime-10);break;case"ArrowRight":t.preventDefault(),this.audioEl.currentTime=Math.min(this.duration,this.currentTime+10);break;case"ArrowUp":t.preventDefault(),this.audioEl.volume=Math.min(1,this.volume+.1),this.audioEl.muted=!1;break;case"ArrowDown":t.preventDefault(),this.audioEl.volume=Math.max(0,this.volume-.1),this.audioEl.muted=0===this.audioEl.volume;break;case"KeyM":t.preventDefault(),this.toggleMute();break;case"KeyR":t.preventDefault(),this.toggleRepeatMode();break;case"KeyS":t.preventDefault(),this.toggleShuffle()}}iconButton(e,s,i,l){const n=document.createElement("button");return n.type="button",n.className=`${a}__control-button`,n.setAttribute("aria-label",s),n.append(t(e,this.getIconSize())),l?.disabled&&(n.disabled=!0),l?.data&&Object.entries(l.data).forEach(([t,e])=>n.setAttribute(`data-${t}`,e)),n.addEventListener("click",i),n}build(){const t=s(this.getAttribute("size"),i,"m"),n=s(this.getAttribute("variant"),l,"default"),o=this.getAttribute("theme")||"auto";this.className=[a,`${a}--size-${t}`,`${a}--variant-${n}`,`${a}--theme-${o}`].join(" "),this.audioEl=document.createElement("audio"),this.audioEl.preload="metadata",this.audioEl.hidden=!0;const r=document.createElement("div");r.className=`${a}__loading`;const h=document.createElement("div");h.className=`${a}__spinner`,r.append(h);const u=document.createElement("div");u.className=`${a}__error`;const d=document.createElement("p");d.textContent="오디오를 재생할 수 없습니다.";const c=document.createElement("button");c.type="button",c.textContent="다시 시도",c.addEventListener("click",()=>window.location.reload()),u.append(d,c);const m=document.createElement("div");m.className=`${a}__album-art`,this.albumImgEl=document.createElement("img"),this.albumImgEl.addEventListener("error",()=>{this.albumImgEl&&(this.albumImgEl.style.display="none"),this.albumPlaceholderEl?.classList.remove("album-placeholder")}),this.albumPlaceholderEl=document.createElement("div"),this.albumPlaceholderEl.className="album-placeholder",this.albumPlaceholderEl.textContent="🎵",m.append(this.albumImgEl,this.albumPlaceholderEl);const p=document.createElement("div");p.className=`${a}__main`;const E=document.createElement("div");E.className=`${a}__info`,this.titleEl=document.createElement("div"),this.titleEl.className=`${a}__title`,this.artistEl=document.createElement("div"),this.artistEl.className=`${a}__artist`,this.albumEl=document.createElement("div"),this.albumEl.className=`${a}__album`,E.append(this.titleEl,this.artistEl,this.albumEl),this.progressEl=document.createElement("div"),this.progressEl.className=`${a}__progress`,this.progressBarEl=document.createElement("div"),this.progressBarEl.className=`${a}__progress-bar`,this.progressHandleEl=document.createElement("div"),this.progressHandleEl.className=`${a}__progress-handle`,this.progressEl.append(this.progressBarEl,this.progressHandleEl),this.progressEl.addEventListener("click",t=>{if(!this.audioEl||!this.progressEl)return;const e=this.progressEl.getBoundingClientRect(),s=(t.clientX-e.left)/e.width;this.audioEl.currentTime=s*(this.duration||0)});const g=document.createElement("div");g.className=`${a}__controls`;const b=document.createElement("div");b.className=`${a}__left-controls`;const y=document.createElement("div");y.className=`${a}__center-controls`;const v=document.createElement("div");v.className=`${a}__right-controls`,this.playButtonEl=document.createElement("button"),this.playButtonEl.type="button",this.playButtonEl.className=`${a}__play-button`,this.playButtonEl.addEventListener("click",()=>this.togglePlay()),y.append(this.playButtonEl),g.append(b,y,v);const f=document.createElement("div");f.className=`${a}__bottom-controls`;const _=document.createElement("div");_.className=`${a}__left-bottom`;const k=document.createElement("div");k.className=`${a}__right-bottom`;const C=document.createElement("div");C.className=`${a}__time`,this.timeCurrentEl=document.createElement("span");const I=document.createElement("span");I.textContent="/",this.timeDurationEl=document.createElement("span"),C.append(this.timeCurrentEl,I,this.timeDurationEl),_.append(C);const $=document.createElement("div");$.className=`${a}__volume`;const A=this.iconButton(this.isMuted||0===this.volume?"mute-filled":"volume-up",this.isMuted||0===this.volume?e("media.unmute"):e("media.mute"),()=>this.toggleMute());A.title=this.isMuted||0===this.volume?"음소거 해제":"음소거";const P=document.createElement("div");P.className=`${a}__volume-slider`;const x=document.createElement("div");x.className="volume-label";const M=document.createElement("span");M.textContent="🔊";const w=document.createElement("span");x.append(M,w),this.volumeInputEl=document.createElement("input"),this.volumeInputEl.type="range",this.volumeInputEl.min="0",this.volumeInputEl.max="1",this.volumeInputEl.step="0.1",this.volumeInputEl.addEventListener("input",()=>{if(!this.audioEl||!this.volumeInputEl)return;const t=parseFloat(this.volumeInputEl.value);this.audioEl.volume=t,this.audioEl.muted=0===t}),P.append(x,this.volumeInputEl),$.append(A,P);const B=document.createElement("div");B.className=`${a}__settings`;const N=this.iconButton("settings",e("media.settings"),()=>{this.showSettingsMenu=!this.showSettingsMenu,this.updateSettingsMenu()});this.settingsMenuEl=document.createElement("div"),this.settingsMenuEl.className=`${a}__settings-menu`,this.settingsMenuEl.hidden=!0;const T=document.createElement("div");T.className=`${a}__setting-group`;const S=document.createElement("label");S.textContent="재생 속도";const R=document.createElement("select");R.addEventListener("change",()=>this.handlePlaybackRateChange(parseFloat(R.value))),T.append(S,R),this.settingsMenuEl.append(T),B.append(N,this.settingsMenuEl),k.append($,B),f.append(_,k),p.append(E,this.progressEl,g,f);const L=document.createElement("div");L.className=`${a}__playlist`,L.hidden=!0;const D=document.createElement("h4");D.textContent="플레이리스트",this.playlistTracksEl=document.createElement("div"),this.playlistTracksEl.className=`${a}__playlist-tracks`,L.append(D,this.playlistTracksEl),this.append(this.audioEl,r,u,m,p,L),this._leftControls=b,this._rightControls=v,this._controls=g,this._time=C,this._volumeWrap=$,this._settings=B,this._playlist=L,this._rateSelect=R,this._volumePercent=w,this._muteButton=A}get leftControls(){return this._leftControls}get rightControls(){return this._rightControls}get controlsEl(){return this._controls}get timeEl(){return this._time}get volumeWrap(){return this._volumeWrap}get settingsEl(){return this._settings}get playlistEl(){return this._playlist}get rateSelect(){return this._rateSelect}get volumePercent(){return this._volumePercent}get muteButton(){return this._muteButton}updateTrackInfo(){const t=this.getCurrentTrack();this.titleEl&&(this.titleEl.textContent=t?.title||"Unknown Track"),this.artistEl&&(this.artistEl.textContent=t?.artist||"Unknown Artist"),this.albumEl&&(t?.album?(this.albumEl.textContent=t.album,this.albumEl.hidden=!1):this.albumEl.hidden=!0),this.albumImgEl&&this.albumPlaceholderEl&&(t?.albumArt?(this.albumImgEl.src=t.albumArt,this.albumImgEl.alt=t.title||"Album Art",this.albumImgEl.style.display=""):(this.albumImgEl.removeAttribute("src"),this.albumImgEl.style.display="none"),this.albumPlaceholderEl.className="album-placeholder")}updateProgress(){const t=this.duration>0?this.currentTime/this.duration*100:0;this.progressBarEl&&(this.progressBarEl.style.width=`${t}%`),this.progressHandleEl&&(this.progressHandleEl.style.left=`${t}%`,this.progressHandleEl.style.transform=t<=0?"translate(0, -50%)":t>=100?"translate(-100%, -50%)":"translate(-50%, -50%)")}updateTime(){this.timeCurrentEl&&(this.timeCurrentEl.textContent=this.formatTime(this.currentTime)),this.timeDurationEl&&(this.timeDurationEl.textContent=this.formatTime(this.duration))}updateVolumeUI(){this.volumeInputEl&&(this.volumeInputEl.value=String(this.volume)),this.volumePercent&&(this.volumePercent.textContent=`${Math.round(100*this.volume)}%`),this.muteButton&&(this.muteButton.replaceChildren(t(this.isMuted||0===this.volume?"mute-filled":"volume-up",this.getIconSize())),this.muteButton.title=this.isMuted||0===this.volume?"음소거 해제":"음소거")}updateSettingsMenu(){this.settingsMenuEl&&(this.settingsMenuEl.hidden=!this.showSettingsMenu)}rebuildControlButtons(){const s=this.getPlaylist(),i=1.2*this.getIconSize();this.leftControls.replaceChildren(),this.rightControls.replaceChildren(),s.length>0&&this.leftControls.append(this.iconButton("refresh",e("media.shuffle"),()=>this.toggleShuffle(),{data:{shuffle:"true"}})),this.leftControls.append(this.iconButton("chevron-left",e("media.previous"),()=>{if(s.length>0){const t=this.playlistIndex-1;t>=0&&this.setPlaylistIndex(t)}else this.audioEl&&(this.audioEl.currentTime=0)},{disabled:s.length>0&&0===this.playlistIndex})),this.playButtonEl&&this.playButtonEl.replaceChildren(t(this.isPlaying?"pause":"play",i)),this.rightControls.append(this.iconButton("chevron-right",e("media.next"),()=>{if(s.length>0){const t=this.playlistIndex+1;t<s.length&&this.setPlaylistIndex(t)}},{disabled:s.length>0&&this.playlistIndex===s.length-1})),s.length>0&&this.rightControls.append(this.iconButton("repeat",e("media.repeat"),()=>this.toggleRepeatMode(),{data:{repeat:"true"}}))}rebuildPlaylist(){if(!this.playlistTracksEl)return;const t=this.getPlaylist(),e=s(this.getAttribute("variant"),l,"default");this.playlistEl.hidden=!("full"===e&&t.length>0),this.playlistTracksEl.replaceChildren(),t.forEach((t,e)=>{const s=document.createElement("div");if(s.className=`${a}__playlist-track${e===this.playlistIndex?` ${a}__playlist-track--active`:""}`,s.addEventListener("click",()=>this.setPlaylistIndex(e)),t.albumArt){const e=document.createElement("img");e.src=t.albumArt,e.alt=t.title||"Album Art",s.append(e)}const i=document.createElement("div");i.className=`${a}__playlist-track-info`;const l=document.createElement("div");l.className=`${a}__playlist-track-title`,l.textContent=t.title||"Unknown Track";const n=document.createElement("div");n.className=`${a}__playlist-track-artist`,n.textContent=t.artist||"Unknown Artist",i.append(l,n),s.append(i),this.playlistTracksEl?.append(s)})}updatePlaylistActive(){this.playlistTracksEl&&Array.from(this.playlistTracksEl.children).forEach((t,e)=>{t.classList.toggle(`${a}__playlist-track--active`,e===this.playlistIndex)})}updateUI(){const t=s(this.getAttribute("size"),i,"m"),e=s(this.getAttribute("variant"),l,"default"),n=this.getAttribute("theme")||"auto",o=this.getBool("show-controls",!0),r=this.getBool("show-progress",!0),h=this.getBool("show-time",!0),u=this.getBool("show-volume",!0),d=this.getBool("show-settings",!1);this.className=[a,`${a}--size-${t}`,`${a}--variant-${e}`,`${a}--theme-${n}`,this.isPlaying&&`${a}--playing`,!this.isPlaying&&`${a}--paused`,this.isMuted&&`${a}--muted`,this.isLoading&&`${a}--loading`,this.error&&`${a}--error`,this.isShuffle&&`${a}--shuffle`,`${a}--repeat-${this.currentRepeatMode}`].filter(Boolean).join(" "),this.audioEl&&(this.audioEl.autoplay=this.getBool("auto-play"),this.audioEl.loop=this.getBool("loop"),this.audioEl.muted=this.getBool("muted"),this.audioEl.playbackRate=this.playbackRate),this.progressEl&&(this.progressEl.hidden=!r),this.controlsEl&&(this.controlsEl.hidden=!o),this.timeEl&&(this.timeEl.hidden=!h),this.volumeWrap&&(this.volumeWrap.hidden=!u),this.settingsEl&&(this.settingsEl.hidden=!d),this.rateSelect.replaceChildren(...this.getPlaybackRates().map(t=>{const e=document.createElement("option");return e.value=String(t),e.textContent=`${t}x`,t===this.playbackRate&&(e.selected=!0),e})),this.rebuildControlButtons(),this.updateTrackInfo(),this.updateProgress(),this.updateTime(),this.updateVolumeUI(),this.updateSettingsMenu(),this.rebuildPlaylist()}}customElements.get("db-audio-player")||customElements.define("db-audio-player",DbAudioPlayer);export{DbAudioPlayer};
|
|
1
|
+
import{dbText as t,t as e}from"../core/i18n.js";import{createDbIcon as s}from"./db-icons.js";import{coerceToContract as i}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{AUDIO_PLAYER_SIZES as l,AUDIO_PLAYER_VARIANTS as a}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const n="designbase-wc-audio-player";class DbAudioPlayer extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.isPlaying=!1,this.isMuted=!1,this.volume=1,this.currentTime=0,this.duration=0,this.showSettingsMenu=!1,this.playbackRate=1,this.currentRepeatMode="none",this.isShuffle=!1,this.isLoading=!1,this.error=null,this.playlistIndex=0,this.shuffledPlaylist=[],this.boundKeyDown=t=>this.handleKeyDown(t)}static get observedAttributes(){return["src","title","artist","album","album-art","size","variant","theme","auto-play","loop","muted","show-controls","enable-keyboard","show-progress","show-time","show-volume","show-settings","playlist","current-index","playback-rates","default-playback-rate","repeat-mode","shuffle"]}connectedCallback(){this.style.display="block",this.built||(this.built=!0,this.build(),this.bindAudioEvents()),this.syncFromAttributes(),this.updateUI(),this.getBool("enable-keyboard",!0)&&document.addEventListener("keydown",this.boundKeyDown)}disconnectedCallback(){document.removeEventListener("keydown",this.boundKeyDown)}attributeChangedCallback(t){if(this.built){if("current-index"===t)return this.playlistIndex=Number(this.getAttribute("current-index")||0),void this.loadCurrentTrack();"repeat-mode"===t&&(this.currentRepeatMode=this.getAttribute("repeat-mode")||"none"),"shuffle"===t&&(this.isShuffle=this.getBool("shuffle"),this.refreshShuffledPlaylist()),"default-playback-rate"===t&&(this.playbackRate=Number(this.getAttribute("default-playback-rate")||1),this.audioEl&&(this.audioEl.playbackRate=this.playbackRate)),this.updateUI()}}getBool(t,e=!1){if(!this.hasAttribute(t))return e;const s=this.getAttribute(t);return""===s||"true"===s}getPlaylist(){try{const t=this.getAttribute("playlist"),e=t?JSON.parse(t):[];return Array.isArray(e)?e:[]}catch{return[]}}getPlaybackRates(){try{const t=this.getAttribute("playback-rates"),e=t?JSON.parse(t):[.5,.75,1,1.25,1.5,2];return Array.isArray(e)&&e.length>0?e:[.5,.75,1,1.25,1.5,2]}catch{return[.5,.75,1,1.25,1.5,2]}}getIconSize(){const t=i(this.getAttribute("size"),l,"m");return"s"===t?16:"l"===t?24:"xl"===t?32:20}getCurrentTrack(){const t=this.getPlaylist();if(t.length>0){return t[this.isShuffle&&this.shuffledPlaylist.length>0?this.shuffledPlaylist[this.playlistIndex]??this.playlistIndex:this.playlistIndex]||t[0]}return{src:this.getAttribute("src")||"",title:this.getAttribute("title")||void 0,artist:this.getAttribute("artist")||void 0,album:this.getAttribute("album")||void 0,albumArt:this.getAttribute("album-art")||void 0}}refreshShuffledPlaylist(){const t=this.getPlaylist();if(t.length>0&&this.isShuffle){const e=Array.from({length:t.length},(t,e)=>e);this.shuffledPlaylist=[...e].sort(()=>Math.random()-.5)}else this.shuffledPlaylist=[]}formatTime(t){return`${Math.floor(t/60)}:${Math.floor(t%60).toString().padStart(2,"0")}`}syncFromAttributes(){this.playlistIndex=Number(this.getAttribute("current-index")||0),this.currentRepeatMode=this.getAttribute("repeat-mode")||"none",this.isShuffle=this.getBool("shuffle"),this.playbackRate=Number(this.getAttribute("default-playback-rate")||1),this.isMuted=this.getBool("muted"),this.volume=this.isMuted?0:1,this.refreshShuffledPlaylist(),this.loadCurrentTrack()}loadCurrentTrack(){if(!this.audioEl)return;const t=this.getCurrentTrack(),e=t?.src||this.getAttribute("src")||"";this.audioEl.src!==e&&e&&(this.audioEl.src=e,this.audioEl.load()),this.updateTrackInfo(),this.updatePlaylistActive()}bindAudioEvents(){const t=this.audioEl;t&&(t.addEventListener("play",()=>{this.isPlaying=!0,this.dispatchEvent(new CustomEvent("db-play",{bubbles:!0,composed:!0})),this.updateUI()}),t.addEventListener("pause",()=>{this.isPlaying=!1,this.dispatchEvent(new CustomEvent("db-pause",{bubbles:!0,composed:!0})),this.updateUI()}),t.addEventListener("timeupdate",()=>{this.currentTime=t.currentTime,this.duration=t.duration||0,this.dispatchEvent(new CustomEvent("db-time-update",{detail:{currentTime:this.currentTime,duration:this.duration},bubbles:!0,composed:!0})),this.updateProgress(),this.updateTime()}),t.addEventListener("volumechange",()=>{this.volume=t.volume,this.isMuted=t.muted,this.dispatchEvent(new CustomEvent("db-volume-change",{detail:{volume:this.volume},bubbles:!0,composed:!0})),this.updateVolumeUI()}),t.addEventListener("ended",()=>this.handleEnded()),t.addEventListener("error",()=>{this.error="오디오를 재생할 수 없습니다.",this.dispatchEvent(new CustomEvent("db-error",{detail:{error:this.error},bubbles:!0,composed:!0})),this.updateUI()}),t.addEventListener("loadstart",()=>{this.isLoading=!0,this.error=null,this.updateUI()}),t.addEventListener("canplay",()=>{this.isLoading=!1,this.updateUI()}))}handleEnded(){this.isPlaying=!1,this.dispatchEvent(new CustomEvent("db-ended",{bubbles:!0,composed:!0}));const t=this.getPlaylist();if(t.length>0){if("one"===this.currentRepeatMode)this.audioEl&&(this.audioEl.currentTime=0,this.audioEl.play());else if("all"===this.currentRepeatMode||this.playlistIndex<t.length-1){const e=this.playlistIndex+1;e<t.length?this.setPlaylistIndex(e):"all"===this.currentRepeatMode&&this.setPlaylistIndex(0)}}else this.getBool("loop")&&this.audioEl&&(this.audioEl.currentTime=0,this.audioEl.play());this.updateUI()}setPlaylistIndex(t){this.playlistIndex=t,this.dispatchEvent(new CustomEvent("db-playlist-change",{detail:{index:t},bubbles:!0,composed:!0})),this.loadCurrentTrack(),this.audioEl&&this.audioEl.play()}togglePlay(){this.audioEl&&(this.isPlaying?this.audioEl.pause():this.audioEl.play())}toggleMute(){this.audioEl&&(this.audioEl.muted=!this.isMuted)}toggleRepeatMode(){const t=["none","one","all"],e=t[(t.indexOf(this.currentRepeatMode)+1)%t.length];this.currentRepeatMode=e,this.dispatchEvent(new CustomEvent("db-repeat-mode-change",{detail:{mode:e},bubbles:!0,composed:!0})),this.updateUI()}toggleShuffle(){this.isShuffle=!this.isShuffle,this.refreshShuffledPlaylist(),this.dispatchEvent(new CustomEvent("db-shuffle-change",{detail:{shuffle:this.isShuffle},bubbles:!0,composed:!0})),this.updateUI()}handlePlaybackRateChange(t){this.audioEl&&(this.audioEl.playbackRate=t,this.playbackRate=t,this.dispatchEvent(new CustomEvent("db-playback-rate-change",{detail:{rate:t},bubbles:!0,composed:!0})))}handleKeyDown(t){if(this.audioEl&&this.getBool("enable-keyboard",!0))switch(t.code){case"Space":t.preventDefault(),this.togglePlay();break;case"ArrowLeft":t.preventDefault(),this.audioEl.currentTime=Math.max(0,this.currentTime-10);break;case"ArrowRight":t.preventDefault(),this.audioEl.currentTime=Math.min(this.duration,this.currentTime+10);break;case"ArrowUp":t.preventDefault(),this.audioEl.volume=Math.min(1,this.volume+.1),this.audioEl.muted=!1;break;case"ArrowDown":t.preventDefault(),this.audioEl.volume=Math.max(0,this.volume-.1),this.audioEl.muted=0===this.audioEl.volume;break;case"KeyM":t.preventDefault(),this.toggleMute();break;case"KeyR":t.preventDefault(),this.toggleRepeatMode();break;case"KeyS":t.preventDefault(),this.toggleShuffle()}}iconButton(t,e,i,l){const a=document.createElement("button");return a.type="button",a.className=`${n}__control-button`,a.setAttribute("aria-label",e),a.append(s(t,this.getIconSize())),l?.disabled&&(a.disabled=!0),l?.data&&Object.entries(l.data).forEach(([t,e])=>a.setAttribute(`data-${t}`,e)),a.addEventListener("click",i),a}build(){const s=i(this.getAttribute("size"),l,"m"),o=i(this.getAttribute("variant"),a,"default"),r=this.getAttribute("theme")||"auto";this.className=[n,`${n}--size-${s}`,`${n}--variant-${o}`,`${n}--theme-${r}`].join(" "),this.audioEl=document.createElement("audio"),this.audioEl.preload="metadata",this.audioEl.hidden=!0;const h=document.createElement("div");h.className=`${n}__loading`;const u=document.createElement("div");u.className=`${n}__spinner`,h.append(u);const d=document.createElement("div");d.className=`${n}__error`;const c=document.createElement("p");c.textContent=t("오디오를 재생할 수 없습니다.");const m=document.createElement("button");m.type="button",m.textContent=t("다시 시도"),m.addEventListener("click",()=>window.location.reload()),d.append(c,m);const p=document.createElement("div");p.className=`${n}__album-art`,this.albumImgEl=document.createElement("img"),this.albumImgEl.addEventListener("error",()=>{this.albumImgEl&&(this.albumImgEl.style.display="none"),this.albumPlaceholderEl?.classList.remove("album-placeholder")}),this.albumPlaceholderEl=document.createElement("div"),this.albumPlaceholderEl.className="album-placeholder",this.albumPlaceholderEl.textContent="🎵",p.append(this.albumImgEl,this.albumPlaceholderEl);const E=document.createElement("div");E.className=`${n}__main`;const g=document.createElement("div");g.className=`${n}__info`,this.titleEl=document.createElement("div"),this.titleEl.className=`${n}__title`,this.artistEl=document.createElement("div"),this.artistEl.className=`${n}__artist`,this.albumEl=document.createElement("div"),this.albumEl.className=`${n}__album`,g.append(this.titleEl,this.artistEl,this.albumEl),this.progressEl=document.createElement("div"),this.progressEl.className=`${n}__progress`,this.progressBarEl=document.createElement("div"),this.progressBarEl.className=`${n}__progress-bar`,this.progressHandleEl=document.createElement("div"),this.progressHandleEl.className=`${n}__progress-handle`,this.progressEl.append(this.progressBarEl,this.progressHandleEl),this.progressEl.addEventListener("click",t=>{if(!this.audioEl||!this.progressEl)return;const e=this.progressEl.getBoundingClientRect(),s=(t.clientX-e.left)/e.width;this.audioEl.currentTime=s*(this.duration||0)});const b=document.createElement("div");b.className=`${n}__controls`;const y=document.createElement("div");y.className=`${n}__left-controls`;const v=document.createElement("div");v.className=`${n}__center-controls`;const f=document.createElement("div");f.className=`${n}__right-controls`,this.playButtonEl=document.createElement("button"),this.playButtonEl.type="button",this.playButtonEl.className=`${n}__play-button`,this.playButtonEl.addEventListener("click",()=>this.togglePlay()),v.append(this.playButtonEl),b.append(y,v,f);const _=document.createElement("div");_.className=`${n}__bottom-controls`;const k=document.createElement("div");k.className=`${n}__left-bottom`;const C=document.createElement("div");C.className=`${n}__right-bottom`;const I=document.createElement("div");I.className=`${n}__time`,this.timeCurrentEl=document.createElement("span");const $=document.createElement("span");$.textContent="/",this.timeDurationEl=document.createElement("span"),I.append(this.timeCurrentEl,$,this.timeDurationEl),k.append(I);const A=document.createElement("div");A.className=`${n}__volume`;const P=this.iconButton(this.isMuted||0===this.volume?"mute-filled":"volume-up",this.isMuted||0===this.volume?e("media.unmute"):e("media.mute"),()=>this.toggleMute());P.title=this.isMuted||0===this.volume?"음소거 해제":"음소거";const x=document.createElement("div");x.className=`${n}__volume-slider`;const M=document.createElement("div");M.className="volume-label";const w=document.createElement("span");w.textContent="🔊";const B=document.createElement("span");M.append(w,B),this.volumeInputEl=document.createElement("input"),this.volumeInputEl.type="range",this.volumeInputEl.min="0",this.volumeInputEl.max="1",this.volumeInputEl.step="0.1",this.volumeInputEl.addEventListener("input",()=>{if(!this.audioEl||!this.volumeInputEl)return;const t=parseFloat(this.volumeInputEl.value);this.audioEl.volume=t,this.audioEl.muted=0===t}),x.append(M,this.volumeInputEl),A.append(P,x);const N=document.createElement("div");N.className=`${n}__settings`;const T=this.iconButton("settings",e("media.settings"),()=>{this.showSettingsMenu=!this.showSettingsMenu,this.updateSettingsMenu()});this.settingsMenuEl=document.createElement("div"),this.settingsMenuEl.className=`${n}__settings-menu`,this.settingsMenuEl.hidden=!0;const S=document.createElement("div");S.className=`${n}__setting-group`;const R=document.createElement("label");R.textContent=t("재생 속도");const L=document.createElement("select");L.addEventListener("change",()=>this.handlePlaybackRateChange(parseFloat(L.value))),S.append(R,L),this.settingsMenuEl.append(S),N.append(T,this.settingsMenuEl),C.append(A,N),_.append(k,C),E.append(g,this.progressEl,b,_);const D=document.createElement("div");D.className=`${n}__playlist`,D.hidden=!0;const U=document.createElement("h4");U.textContent=t("플레이리스트"),this.playlistTracksEl=document.createElement("div"),this.playlistTracksEl.className=`${n}__playlist-tracks`,D.append(U,this.playlistTracksEl),this.append(this.audioEl,h,d,p,E,D),this._leftControls=y,this._rightControls=f,this._controls=b,this._time=I,this._volumeWrap=A,this._settings=N,this._playlist=D,this._rateSelect=L,this._volumePercent=B,this._muteButton=P}get leftControls(){return this._leftControls}get rightControls(){return this._rightControls}get controlsEl(){return this._controls}get timeEl(){return this._time}get volumeWrap(){return this._volumeWrap}get settingsEl(){return this._settings}get playlistEl(){return this._playlist}get rateSelect(){return this._rateSelect}get volumePercent(){return this._volumePercent}get muteButton(){return this._muteButton}updateTrackInfo(){const t=this.getCurrentTrack();this.titleEl&&(this.titleEl.textContent=t?.title||"Unknown Track"),this.artistEl&&(this.artistEl.textContent=t?.artist||"Unknown Artist"),this.albumEl&&(t?.album?(this.albumEl.textContent=t.album,this.albumEl.hidden=!1):this.albumEl.hidden=!0),this.albumImgEl&&this.albumPlaceholderEl&&(t?.albumArt?(this.albumImgEl.src=t.albumArt,this.albumImgEl.alt=t.title||"Album Art",this.albumImgEl.style.display=""):(this.albumImgEl.removeAttribute("src"),this.albumImgEl.style.display="none"),this.albumPlaceholderEl.className="album-placeholder")}updateProgress(){const t=this.duration>0?this.currentTime/this.duration*100:0;this.progressBarEl&&(this.progressBarEl.style.width=`${t}%`),this.progressHandleEl&&(this.progressHandleEl.style.left=`${t}%`,this.progressHandleEl.style.transform=t<=0?"translate(0, -50%)":t>=100?"translate(-100%, -50%)":"translate(-50%, -50%)")}updateTime(){this.timeCurrentEl&&(this.timeCurrentEl.textContent=this.formatTime(this.currentTime)),this.timeDurationEl&&(this.timeDurationEl.textContent=this.formatTime(this.duration))}updateVolumeUI(){this.volumeInputEl&&(this.volumeInputEl.value=String(this.volume)),this.volumePercent&&(this.volumePercent.textContent=`${Math.round(100*this.volume)}%`),this.muteButton&&(this.muteButton.replaceChildren(s(this.isMuted||0===this.volume?"mute-filled":"volume-up",this.getIconSize())),this.muteButton.title=this.isMuted||0===this.volume?"음소거 해제":"음소거")}updateSettingsMenu(){this.settingsMenuEl&&(this.settingsMenuEl.hidden=!this.showSettingsMenu)}rebuildControlButtons(){const t=this.getPlaylist(),i=1.2*this.getIconSize();this.leftControls.replaceChildren(),this.rightControls.replaceChildren(),t.length>0&&this.leftControls.append(this.iconButton("refresh",e("media.shuffle"),()=>this.toggleShuffle(),{data:{shuffle:"true"}})),this.leftControls.append(this.iconButton("chevron-left",e("media.previous"),()=>{if(t.length>0){const t=this.playlistIndex-1;t>=0&&this.setPlaylistIndex(t)}else this.audioEl&&(this.audioEl.currentTime=0)},{disabled:t.length>0&&0===this.playlistIndex})),this.playButtonEl&&this.playButtonEl.replaceChildren(s(this.isPlaying?"pause":"play",i)),this.rightControls.append(this.iconButton("chevron-right",e("media.next"),()=>{if(t.length>0){const e=this.playlistIndex+1;e<t.length&&this.setPlaylistIndex(e)}},{disabled:t.length>0&&this.playlistIndex===t.length-1})),t.length>0&&this.rightControls.append(this.iconButton("repeat",e("media.repeat"),()=>this.toggleRepeatMode(),{data:{repeat:"true"}}))}rebuildPlaylist(){if(!this.playlistTracksEl)return;const t=this.getPlaylist(),e=i(this.getAttribute("variant"),a,"default");this.playlistEl.hidden=!("full"===e&&t.length>0),this.playlistTracksEl.replaceChildren(),t.forEach((t,e)=>{const s=document.createElement("div");if(s.className=`${n}__playlist-track${e===this.playlistIndex?` ${n}__playlist-track--active`:""}`,s.addEventListener("click",()=>this.setPlaylistIndex(e)),t.albumArt){const e=document.createElement("img");e.src=t.albumArt,e.alt=t.title||"Album Art",s.append(e)}const i=document.createElement("div");i.className=`${n}__playlist-track-info`;const l=document.createElement("div");l.className=`${n}__playlist-track-title`,l.textContent=t.title||"Unknown Track";const a=document.createElement("div");a.className=`${n}__playlist-track-artist`,a.textContent=t.artist||"Unknown Artist",i.append(l,a),s.append(i),this.playlistTracksEl?.append(s)})}updatePlaylistActive(){this.playlistTracksEl&&Array.from(this.playlistTracksEl.children).forEach((t,e)=>{t.classList.toggle(`${n}__playlist-track--active`,e===this.playlistIndex)})}updateUI(){const t=i(this.getAttribute("size"),l,"m"),e=i(this.getAttribute("variant"),a,"default"),s=this.getAttribute("theme")||"auto",o=this.getBool("show-controls",!0),r=this.getBool("show-progress",!0),h=this.getBool("show-time",!0),u=this.getBool("show-volume",!0),d=this.getBool("show-settings",!1);this.className=[n,`${n}--size-${t}`,`${n}--variant-${e}`,`${n}--theme-${s}`,this.isPlaying&&`${n}--playing`,!this.isPlaying&&`${n}--paused`,this.isMuted&&`${n}--muted`,this.isLoading&&`${n}--loading`,this.error&&`${n}--error`,this.isShuffle&&`${n}--shuffle`,`${n}--repeat-${this.currentRepeatMode}`].filter(Boolean).join(" "),this.audioEl&&(this.audioEl.autoplay=this.getBool("auto-play"),this.audioEl.loop=this.getBool("loop"),this.audioEl.muted=this.getBool("muted"),this.audioEl.playbackRate=this.playbackRate),this.progressEl&&(this.progressEl.hidden=!r),this.controlsEl&&(this.controlsEl.hidden=!o),this.timeEl&&(this.timeEl.hidden=!h),this.volumeWrap&&(this.volumeWrap.hidden=!u),this.settingsEl&&(this.settingsEl.hidden=!d),this.rateSelect.replaceChildren(...this.getPlaybackRates().map(t=>{const e=document.createElement("option");return e.value=String(t),e.textContent=`${t}x`,t===this.playbackRate&&(e.selected=!0),e})),this.rebuildControlButtons(),this.updateTrackInfo(),this.updateProgress(),this.updateTime(),this.updateVolumeUI(),this.updateSettingsMenu(),this.rebuildPlaylist()}}customElements.get("db-audio-player")||customElements.define("db-audio-player",DbAudioPlayer);export{DbAudioPlayer};
|